endoreg-db 0.8.8.9__py3-none-any.whl → 0.8.9.10__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 endoreg-db might be problematic. Click here for more details.

Files changed (453) hide show
  1. endoreg_db/admin.py +10 -5
  2. endoreg_db/apps.py +4 -7
  3. endoreg_db/authz/auth.py +1 -0
  4. endoreg_db/authz/backends.py +1 -1
  5. endoreg_db/authz/management/commands/list_routes.py +2 -0
  6. endoreg_db/authz/middleware.py +8 -7
  7. endoreg_db/authz/permissions.py +21 -10
  8. endoreg_db/authz/policy.py +14 -19
  9. endoreg_db/authz/views_auth.py +14 -10
  10. endoreg_db/codemods/rename_datetime_fields.py +8 -1
  11. endoreg_db/exceptions.py +5 -2
  12. endoreg_db/forms/__init__.py +0 -1
  13. endoreg_db/forms/examination_form.py +4 -3
  14. endoreg_db/forms/patient_finding_intervention_form.py +30 -8
  15. endoreg_db/forms/patient_form.py +9 -13
  16. endoreg_db/forms/questionnaires/__init__.py +1 -1
  17. endoreg_db/forms/settings/__init__.py +4 -1
  18. endoreg_db/forms/unit.py +2 -1
  19. endoreg_db/helpers/count_db.py +17 -14
  20. endoreg_db/helpers/default_objects.py +2 -1
  21. endoreg_db/helpers/download_segmentation_model.py +4 -3
  22. endoreg_db/helpers/interact.py +0 -5
  23. endoreg_db/helpers/test_video_helper.py +33 -25
  24. endoreg_db/import_files/__init__.py +1 -1
  25. endoreg_db/import_files/context/__init__.py +1 -1
  26. endoreg_db/import_files/context/default_sensitive_meta.py +11 -9
  27. endoreg_db/import_files/context/ensure_center.py +4 -4
  28. endoreg_db/import_files/context/file_lock.py +3 -3
  29. endoreg_db/import_files/context/import_context.py +11 -12
  30. endoreg_db/import_files/context/validate_directories.py +1 -0
  31. endoreg_db/import_files/file_storage/create_report_file.py +57 -34
  32. endoreg_db/import_files/file_storage/create_video_file.py +64 -35
  33. endoreg_db/import_files/file_storage/sensitive_meta_storage.py +5 -2
  34. endoreg_db/import_files/file_storage/state_management.py +146 -83
  35. endoreg_db/import_files/file_storage/storage.py +5 -1
  36. endoreg_db/import_files/processing/report_processing/report_anonymization.py +24 -19
  37. endoreg_db/import_files/processing/sensitive_meta_adapter.py +3 -3
  38. endoreg_db/import_files/processing/video_processing/video_anonymization.py +18 -18
  39. endoreg_db/import_files/pseudonymization/k_anonymity.py +8 -9
  40. endoreg_db/import_files/pseudonymization/k_pseudonymity.py +16 -5
  41. endoreg_db/import_files/report_import_service.py +36 -30
  42. endoreg_db/import_files/video_import_service.py +27 -23
  43. endoreg_db/logger_conf.py +56 -40
  44. endoreg_db/management/__init__.py +1 -1
  45. endoreg_db/management/commands/__init__.py +1 -1
  46. endoreg_db/management/commands/check_auth.py +45 -38
  47. endoreg_db/management/commands/create_model_meta_from_huggingface.py +53 -2
  48. endoreg_db/management/commands/create_multilabel_model_meta.py +54 -19
  49. endoreg_db/management/commands/fix_missing_patient_data.py +105 -71
  50. endoreg_db/management/commands/fix_video_paths.py +75 -54
  51. endoreg_db/management/commands/import_report.py +1 -3
  52. endoreg_db/management/commands/list_routes.py +2 -0
  53. endoreg_db/management/commands/load_ai_model_data.py +8 -2
  54. endoreg_db/management/commands/load_ai_model_label_data.py +0 -1
  55. endoreg_db/management/commands/load_center_data.py +3 -3
  56. endoreg_db/management/commands/load_distribution_data.py +35 -38
  57. endoreg_db/management/commands/load_endoscope_data.py +0 -3
  58. endoreg_db/management/commands/load_examination_data.py +20 -4
  59. endoreg_db/management/commands/load_finding_data.py +18 -3
  60. endoreg_db/management/commands/load_gender_data.py +17 -24
  61. endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +95 -85
  62. endoreg_db/management/commands/load_information_source.py +0 -3
  63. endoreg_db/management/commands/load_lab_value_data.py +14 -3
  64. endoreg_db/management/commands/load_legacy_data.py +303 -0
  65. endoreg_db/management/commands/load_name_data.py +1 -2
  66. endoreg_db/management/commands/load_pdf_type_data.py +4 -8
  67. endoreg_db/management/commands/load_profession_data.py +0 -1
  68. endoreg_db/management/commands/load_report_reader_flag_data.py +0 -4
  69. endoreg_db/management/commands/load_requirement_data.py +6 -2
  70. endoreg_db/management/commands/load_unit_data.py +0 -4
  71. endoreg_db/management/commands/load_user_groups.py +5 -7
  72. endoreg_db/management/commands/model_input.py +169 -0
  73. endoreg_db/management/commands/register_ai_model.py +22 -16
  74. endoreg_db/management/commands/setup_endoreg_db.py +110 -32
  75. endoreg_db/management/commands/storage_management.py +14 -8
  76. endoreg_db/management/commands/summarize_db_content.py +154 -63
  77. endoreg_db/management/commands/train_image_multilabel_model.py +144 -0
  78. endoreg_db/management/commands/validate_video_files.py +82 -50
  79. endoreg_db/management/commands/video_validation.py +4 -6
  80. endoreg_db/migrations/0001_initial.py +112 -63
  81. endoreg_db/migrations/__init__.py +0 -0
  82. endoreg_db/models/__init__.py +8 -0
  83. endoreg_db/models/administration/ai/active_model.py +5 -5
  84. endoreg_db/models/administration/ai/ai_model.py +41 -18
  85. endoreg_db/models/administration/ai/model_type.py +1 -0
  86. endoreg_db/models/administration/case/case.py +22 -22
  87. endoreg_db/models/administration/center/__init__.py +5 -5
  88. endoreg_db/models/administration/center/center.py +6 -2
  89. endoreg_db/models/administration/center/center_resource.py +18 -4
  90. endoreg_db/models/administration/center/center_shift.py +3 -1
  91. endoreg_db/models/administration/center/center_waste.py +6 -2
  92. endoreg_db/models/administration/person/__init__.py +1 -1
  93. endoreg_db/models/administration/person/employee/__init__.py +1 -1
  94. endoreg_db/models/administration/person/employee/employee_type.py +3 -1
  95. endoreg_db/models/administration/person/examiner/__init__.py +1 -1
  96. endoreg_db/models/administration/person/examiner/examiner.py +10 -2
  97. endoreg_db/models/administration/person/names/first_name.py +6 -4
  98. endoreg_db/models/administration/person/names/last_name.py +4 -3
  99. endoreg_db/models/administration/person/patient/__init__.py +1 -1
  100. endoreg_db/models/administration/person/patient/patient.py +0 -1
  101. endoreg_db/models/administration/person/patient/patient_external_id.py +0 -1
  102. endoreg_db/models/administration/person/person.py +1 -1
  103. endoreg_db/models/administration/product/__init__.py +7 -6
  104. endoreg_db/models/administration/product/product.py +6 -2
  105. endoreg_db/models/administration/product/product_group.py +9 -7
  106. endoreg_db/models/administration/product/product_material.py +9 -2
  107. endoreg_db/models/administration/product/reference_product.py +64 -15
  108. endoreg_db/models/administration/qualification/qualification.py +3 -1
  109. endoreg_db/models/administration/shift/shift.py +3 -1
  110. endoreg_db/models/administration/shift/shift_type.py +12 -4
  111. endoreg_db/models/aidataset/__init__.py +5 -0
  112. endoreg_db/models/aidataset/aidataset.py +193 -0
  113. endoreg_db/models/label/__init__.py +1 -1
  114. endoreg_db/models/label/label.py +10 -2
  115. endoreg_db/models/label/label_set.py +3 -1
  116. endoreg_db/models/label/label_video_segment/_create_from_video.py +6 -2
  117. endoreg_db/models/label/label_video_segment/label_video_segment.py +148 -44
  118. endoreg_db/models/media/__init__.py +12 -5
  119. endoreg_db/models/media/frame/__init__.py +1 -1
  120. endoreg_db/models/media/frame/frame.py +34 -8
  121. endoreg_db/models/media/pdf/__init__.py +2 -1
  122. endoreg_db/models/media/pdf/raw_pdf.py +11 -4
  123. endoreg_db/models/media/pdf/report_file.py +6 -2
  124. endoreg_db/models/media/pdf/report_reader/__init__.py +3 -3
  125. endoreg_db/models/media/pdf/report_reader/report_reader_flag.py +15 -5
  126. endoreg_db/models/media/video/create_from_file.py +20 -41
  127. endoreg_db/models/media/video/pipe_1.py +75 -30
  128. endoreg_db/models/media/video/pipe_2.py +37 -12
  129. endoreg_db/models/media/video/video_file.py +36 -24
  130. endoreg_db/models/media/video/video_file_ai.py +235 -70
  131. endoreg_db/models/media/video/video_file_anonymize.py +240 -65
  132. endoreg_db/models/media/video/video_file_frames/_bulk_create_frames.py +6 -1
  133. endoreg_db/models/media/video/video_file_frames/_create_frame_object.py +3 -1
  134. endoreg_db/models/media/video/video_file_frames/_delete_frames.py +30 -9
  135. endoreg_db/models/media/video/video_file_frames/_extract_frames.py +95 -29
  136. endoreg_db/models/media/video/video_file_frames/_get_frame.py +13 -3
  137. endoreg_db/models/media/video/video_file_frames/_get_frame_path.py +4 -1
  138. endoreg_db/models/media/video/video_file_frames/_get_frame_paths.py +15 -3
  139. endoreg_db/models/media/video/video_file_frames/_get_frame_range.py +15 -3
  140. endoreg_db/models/media/video/video_file_frames/_get_frames.py +7 -2
  141. endoreg_db/models/media/video/video_file_frames/_initialize_frames.py +109 -23
  142. endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +111 -27
  143. endoreg_db/models/media/video/video_file_frames/_mark_frames_extracted_status.py +46 -13
  144. endoreg_db/models/media/video/video_file_io.py +85 -33
  145. endoreg_db/models/media/video/video_file_meta/__init__.py +6 -6
  146. endoreg_db/models/media/video/video_file_meta/get_crop_template.py +17 -4
  147. endoreg_db/models/media/video/video_file_meta/get_endo_roi.py +28 -7
  148. endoreg_db/models/media/video/video_file_meta/get_fps.py +46 -13
  149. endoreg_db/models/media/video/video_file_meta/initialize_video_specs.py +81 -20
  150. endoreg_db/models/media/video/video_file_meta/text_meta.py +61 -20
  151. endoreg_db/models/media/video/video_file_meta/video_meta.py +40 -12
  152. endoreg_db/models/media/video/video_file_segments.py +118 -27
  153. endoreg_db/models/media/video/video_metadata.py +25 -6
  154. endoreg_db/models/media/video/video_processing.py +54 -15
  155. endoreg_db/models/medical/__init__.py +3 -13
  156. endoreg_db/models/medical/contraindication/__init__.py +3 -1
  157. endoreg_db/models/medical/disease.py +18 -6
  158. endoreg_db/models/medical/event.py +6 -2
  159. endoreg_db/models/medical/examination/__init__.py +5 -1
  160. endoreg_db/models/medical/examination/examination.py +22 -6
  161. endoreg_db/models/medical/examination/examination_indication.py +23 -7
  162. endoreg_db/models/medical/examination/examination_time.py +6 -2
  163. endoreg_db/models/medical/finding/__init__.py +3 -1
  164. endoreg_db/models/medical/finding/finding.py +37 -12
  165. endoreg_db/models/medical/finding/finding_classification.py +27 -8
  166. endoreg_db/models/medical/finding/finding_intervention.py +19 -6
  167. endoreg_db/models/medical/finding/finding_type.py +3 -1
  168. endoreg_db/models/medical/hardware/__init__.py +1 -1
  169. endoreg_db/models/medical/hardware/endoscope.py +14 -2
  170. endoreg_db/models/medical/laboratory/__init__.py +1 -1
  171. endoreg_db/models/medical/laboratory/lab_value.py +139 -39
  172. endoreg_db/models/medical/medication/__init__.py +7 -3
  173. endoreg_db/models/medical/medication/medication.py +3 -1
  174. endoreg_db/models/medical/medication/medication_indication.py +3 -1
  175. endoreg_db/models/medical/medication/medication_indication_type.py +11 -3
  176. endoreg_db/models/medical/medication/medication_intake_time.py +3 -1
  177. endoreg_db/models/medical/medication/medication_schedule.py +3 -1
  178. endoreg_db/models/medical/patient/__init__.py +2 -10
  179. endoreg_db/models/medical/patient/medication_examples.py +3 -14
  180. endoreg_db/models/medical/patient/patient_disease.py +17 -5
  181. endoreg_db/models/medical/patient/patient_event.py +12 -4
  182. endoreg_db/models/medical/patient/patient_examination.py +52 -15
  183. endoreg_db/models/medical/patient/patient_examination_indication.py +15 -4
  184. endoreg_db/models/medical/patient/patient_finding.py +105 -29
  185. endoreg_db/models/medical/patient/patient_finding_classification.py +41 -12
  186. endoreg_db/models/medical/patient/patient_finding_intervention.py +11 -3
  187. endoreg_db/models/medical/patient/patient_lab_sample.py +6 -2
  188. endoreg_db/models/medical/patient/patient_lab_value.py +42 -10
  189. endoreg_db/models/medical/patient/patient_medication.py +25 -7
  190. endoreg_db/models/medical/patient/patient_medication_schedule.py +34 -10
  191. endoreg_db/models/metadata/model_meta.py +40 -12
  192. endoreg_db/models/metadata/model_meta_logic.py +51 -16
  193. endoreg_db/models/metadata/sensitive_meta.py +65 -28
  194. endoreg_db/models/metadata/sensitive_meta_logic.py +28 -26
  195. endoreg_db/models/metadata/video_meta.py +146 -39
  196. endoreg_db/models/metadata/video_prediction_logic.py +70 -21
  197. endoreg_db/models/metadata/video_prediction_meta.py +80 -27
  198. endoreg_db/models/operation_log.py +63 -0
  199. endoreg_db/models/other/__init__.py +10 -10
  200. endoreg_db/models/other/distribution/__init__.py +9 -7
  201. endoreg_db/models/other/distribution/base_value_distribution.py +3 -1
  202. endoreg_db/models/other/distribution/date_value_distribution.py +19 -5
  203. endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +3 -1
  204. endoreg_db/models/other/distribution/numeric_value_distribution.py +34 -9
  205. endoreg_db/models/other/emission/__init__.py +1 -1
  206. endoreg_db/models/other/emission/emission_factor.py +9 -3
  207. endoreg_db/models/other/information_source.py +15 -5
  208. endoreg_db/models/other/material.py +3 -1
  209. endoreg_db/models/other/transport_route.py +3 -1
  210. endoreg_db/models/other/unit.py +6 -2
  211. endoreg_db/models/report/report.py +0 -1
  212. endoreg_db/models/requirement/requirement.py +84 -27
  213. endoreg_db/models/requirement/requirement_error.py +5 -6
  214. endoreg_db/models/requirement/requirement_evaluation/__init__.py +1 -1
  215. endoreg_db/models/requirement/requirement_evaluation/evaluate_with_dependencies.py +8 -8
  216. endoreg_db/models/requirement/requirement_evaluation/get_values.py +3 -3
  217. endoreg_db/models/requirement/requirement_evaluation/requirement_type_parser.py +24 -8
  218. endoreg_db/models/requirement/requirement_operator.py +28 -8
  219. endoreg_db/models/requirement/requirement_set.py +34 -11
  220. endoreg_db/models/state/__init__.py +1 -0
  221. endoreg_db/models/state/audit_ledger.py +9 -2
  222. endoreg_db/models/{media → state}/processing_history/__init__.py +1 -3
  223. endoreg_db/models/state/processing_history/processing_history.py +136 -0
  224. endoreg_db/models/state/raw_pdf.py +0 -1
  225. endoreg_db/models/state/video.py +2 -3
  226. endoreg_db/models/utils.py +4 -2
  227. endoreg_db/queries/__init__.py +2 -6
  228. endoreg_db/queries/annotations/__init__.py +1 -3
  229. endoreg_db/queries/annotations/legacy.py +37 -26
  230. endoreg_db/root_urls.py +3 -4
  231. endoreg_db/schemas/examination_evaluation.py +3 -0
  232. endoreg_db/serializers/Frames_NICE_and_PARIS_classifications.py +249 -163
  233. endoreg_db/serializers/__init__.py +2 -8
  234. endoreg_db/serializers/administration/__init__.py +1 -2
  235. endoreg_db/serializers/administration/ai/__init__.py +0 -1
  236. endoreg_db/serializers/administration/ai/active_model.py +3 -1
  237. endoreg_db/serializers/administration/ai/ai_model.py +5 -3
  238. endoreg_db/serializers/administration/ai/model_type.py +3 -1
  239. endoreg_db/serializers/administration/center.py +7 -2
  240. endoreg_db/serializers/administration/gender.py +4 -2
  241. endoreg_db/serializers/anonymization.py +13 -13
  242. endoreg_db/serializers/evaluation/examination_evaluation.py +0 -1
  243. endoreg_db/serializers/examination/__init__.py +1 -1
  244. endoreg_db/serializers/examination/base.py +12 -13
  245. endoreg_db/serializers/examination/dropdown.py +6 -7
  246. endoreg_db/serializers/examination_serializer.py +3 -6
  247. endoreg_db/serializers/finding/__init__.py +1 -1
  248. endoreg_db/serializers/finding/finding.py +14 -7
  249. endoreg_db/serializers/finding_classification/__init__.py +3 -3
  250. endoreg_db/serializers/finding_classification/choice.py +3 -3
  251. endoreg_db/serializers/finding_classification/classification.py +2 -4
  252. endoreg_db/serializers/label_video_segment/__init__.py +5 -3
  253. endoreg_db/serializers/{label → label_video_segment}/image_classification_annotation.py +5 -5
  254. endoreg_db/serializers/label_video_segment/label/__init__.py +6 -0
  255. endoreg_db/serializers/{label → label_video_segment/label}/label.py +1 -1
  256. endoreg_db/serializers/label_video_segment/label_video_segment.py +338 -228
  257. endoreg_db/serializers/meta/__init__.py +1 -2
  258. endoreg_db/serializers/meta/sensitive_meta_detail.py +28 -13
  259. endoreg_db/serializers/meta/sensitive_meta_update.py +51 -46
  260. endoreg_db/serializers/meta/sensitive_meta_verification.py +19 -16
  261. endoreg_db/serializers/misc/__init__.py +2 -2
  262. endoreg_db/serializers/misc/file_overview.py +11 -7
  263. endoreg_db/serializers/misc/stats.py +10 -8
  264. endoreg_db/serializers/misc/translatable_field_mix_in.py +6 -6
  265. endoreg_db/serializers/misc/upload_job.py +32 -29
  266. endoreg_db/serializers/patient/__init__.py +2 -1
  267. endoreg_db/serializers/patient/patient.py +32 -15
  268. endoreg_db/serializers/patient/patient_dropdown.py +11 -3
  269. endoreg_db/serializers/patient_examination/__init__.py +1 -1
  270. endoreg_db/serializers/patient_examination/patient_examination.py +67 -40
  271. endoreg_db/serializers/patient_finding/__init__.py +1 -1
  272. endoreg_db/serializers/patient_finding/patient_finding.py +2 -1
  273. endoreg_db/serializers/patient_finding/patient_finding_classification.py +17 -9
  274. endoreg_db/serializers/patient_finding/patient_finding_detail.py +26 -17
  275. endoreg_db/serializers/patient_finding/patient_finding_intervention.py +7 -5
  276. endoreg_db/serializers/patient_finding/patient_finding_list.py +10 -11
  277. endoreg_db/serializers/patient_finding/patient_finding_write.py +36 -27
  278. endoreg_db/serializers/pdf/__init__.py +1 -3
  279. endoreg_db/serializers/requirements/requirement_schema.py +1 -6
  280. endoreg_db/serializers/sensitive_meta_serializer.py +100 -81
  281. endoreg_db/serializers/video/__init__.py +2 -2
  282. endoreg_db/serializers/video/{segmentation.py → video_file.py} +66 -47
  283. endoreg_db/serializers/video/video_file_brief.py +6 -2
  284. endoreg_db/serializers/video/video_file_detail.py +36 -23
  285. endoreg_db/serializers/video/video_file_list.py +4 -2
  286. endoreg_db/serializers/video/video_processing_history.py +54 -50
  287. endoreg_db/services/__init__.py +1 -1
  288. endoreg_db/services/anonymization.py +2 -2
  289. endoreg_db/services/examination_evaluation.py +40 -17
  290. endoreg_db/services/model_meta_from_hf.py +76 -0
  291. endoreg_db/services/polling_coordinator.py +101 -70
  292. endoreg_db/services/pseudonym_service.py +27 -22
  293. endoreg_db/services/report_import.py +6 -3
  294. endoreg_db/services/segment_sync.py +75 -59
  295. endoreg_db/services/video_import.py +6 -7
  296. endoreg_db/urls/__init__.py +2 -2
  297. endoreg_db/urls/ai.py +7 -25
  298. endoreg_db/urls/anonymization.py +61 -15
  299. endoreg_db/urls/auth.py +4 -4
  300. endoreg_db/urls/classification.py +4 -9
  301. endoreg_db/urls/examination.py +27 -18
  302. endoreg_db/urls/media.py +27 -34
  303. endoreg_db/urls/patient.py +11 -7
  304. endoreg_db/urls/requirements.py +3 -1
  305. endoreg_db/urls/root_urls.py +2 -3
  306. endoreg_db/urls/stats.py +24 -16
  307. endoreg_db/urls/upload.py +3 -11
  308. endoreg_db/utils/__init__.py +14 -15
  309. endoreg_db/utils/ai/__init__.py +1 -1
  310. endoreg_db/utils/ai/data_loader_for_model_input.py +262 -0
  311. endoreg_db/utils/ai/data_loader_for_model_training.py +262 -0
  312. endoreg_db/utils/ai/get.py +2 -1
  313. endoreg_db/utils/ai/inference_dataset.py +14 -15
  314. endoreg_db/utils/ai/model_training/config.py +117 -0
  315. endoreg_db/utils/ai/model_training/dataset.py +74 -0
  316. endoreg_db/utils/ai/model_training/losses.py +68 -0
  317. endoreg_db/utils/ai/model_training/metrics.py +78 -0
  318. endoreg_db/utils/ai/model_training/model_backbones.py +155 -0
  319. endoreg_db/utils/ai/model_training/model_gastronet_resnet.py +118 -0
  320. endoreg_db/utils/ai/model_training/trainer_gastronet_multilabel.py +771 -0
  321. endoreg_db/utils/ai/multilabel_classification_net.py +21 -6
  322. endoreg_db/utils/ai/predict.py +4 -4
  323. endoreg_db/utils/ai/preprocess.py +19 -11
  324. endoreg_db/utils/calc_duration_seconds.py +4 -4
  325. endoreg_db/utils/case_generator/lab_sample_factory.py +3 -4
  326. endoreg_db/utils/check_video_files.py +74 -47
  327. endoreg_db/utils/cropping.py +10 -9
  328. endoreg_db/utils/dataloader.py +11 -3
  329. endoreg_db/utils/dates.py +3 -4
  330. endoreg_db/utils/defaults/set_default_center.py +7 -6
  331. endoreg_db/utils/env.py +6 -2
  332. endoreg_db/utils/extract_specific_frames.py +24 -9
  333. endoreg_db/utils/file_operations.py +30 -18
  334. endoreg_db/utils/fix_video_path_direct.py +57 -41
  335. endoreg_db/utils/frame_anonymization_utils.py +157 -157
  336. endoreg_db/utils/hashs.py +3 -18
  337. endoreg_db/utils/links/requirement_link.py +96 -52
  338. endoreg_db/utils/ocr.py +30 -25
  339. endoreg_db/utils/operation_log.py +61 -0
  340. endoreg_db/utils/parse_and_generate_yaml.py +12 -13
  341. endoreg_db/utils/paths.py +6 -6
  342. endoreg_db/utils/permissions.py +40 -24
  343. endoreg_db/utils/pipelines/process_video_dir.py +50 -26
  344. endoreg_db/utils/product/sum_emissions.py +5 -3
  345. endoreg_db/utils/product/sum_weights.py +4 -2
  346. endoreg_db/utils/pydantic_models/__init__.py +3 -4
  347. endoreg_db/utils/requirement_operator_logic/_old/lab_value_operators.py +207 -107
  348. endoreg_db/utils/requirement_operator_logic/_old/model_evaluators.py +252 -65
  349. endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +27 -10
  350. endoreg_db/utils/setup_config.py +21 -5
  351. endoreg_db/utils/storage.py +3 -1
  352. endoreg_db/utils/translation.py +19 -15
  353. endoreg_db/utils/uuid.py +1 -0
  354. endoreg_db/utils/validate_endo_roi.py +12 -4
  355. endoreg_db/utils/validate_subcategory_dict.py +26 -24
  356. endoreg_db/utils/validate_video_detailed.py +207 -149
  357. endoreg_db/utils/video/__init__.py +7 -3
  358. endoreg_db/utils/video/extract_frames.py +30 -18
  359. endoreg_db/utils/video/ffmpeg_wrapper.py +217 -52
  360. endoreg_db/utils/video/names.py +11 -6
  361. endoreg_db/utils/video/streaming_processor.py +175 -101
  362. endoreg_db/utils/video/video_splitter.py +30 -19
  363. endoreg_db/views/Frames_NICE_and_PARIS_classifications_views.py +59 -50
  364. endoreg_db/views/__init__.py +0 -20
  365. endoreg_db/views/anonymization/__init__.py +6 -2
  366. endoreg_db/views/anonymization/media_management.py +2 -6
  367. endoreg_db/views/anonymization/overview.py +34 -1
  368. endoreg_db/views/anonymization/validate.py +79 -18
  369. endoreg_db/views/auth/__init__.py +1 -1
  370. endoreg_db/views/auth/keycloak.py +16 -14
  371. endoreg_db/views/examination/__init__.py +12 -15
  372. endoreg_db/views/examination/examination.py +5 -5
  373. endoreg_db/views/examination/examination_manifest_cache.py +5 -5
  374. endoreg_db/views/examination/get_finding_classification_choices.py +8 -5
  375. endoreg_db/views/examination/get_finding_classifications.py +9 -7
  376. endoreg_db/views/examination/get_findings.py +8 -10
  377. endoreg_db/views/examination/get_instruments.py +3 -2
  378. endoreg_db/views/examination/get_interventions.py +1 -1
  379. endoreg_db/views/finding/__init__.py +2 -2
  380. endoreg_db/views/finding/finding.py +58 -54
  381. endoreg_db/views/finding/get_classifications.py +1 -1
  382. endoreg_db/views/finding/get_interventions.py +1 -1
  383. endoreg_db/views/finding_classification/__init__.py +5 -5
  384. endoreg_db/views/finding_classification/finding_classification.py +5 -6
  385. endoreg_db/views/finding_classification/get_classification_choices.py +3 -4
  386. endoreg_db/views/media/__init__.py +13 -13
  387. endoreg_db/views/media/pdf_media.py +9 -9
  388. endoreg_db/views/media/sensitive_metadata.py +10 -7
  389. endoreg_db/views/media/video_media.py +4 -4
  390. endoreg_db/views/meta/__init__.py +1 -1
  391. endoreg_db/views/meta/sensitive_meta_list.py +20 -22
  392. endoreg_db/views/meta/sensitive_meta_verification.py +14 -11
  393. endoreg_db/views/misc/__init__.py +6 -34
  394. endoreg_db/views/misc/center.py +2 -1
  395. endoreg_db/views/misc/csrf.py +2 -1
  396. endoreg_db/views/misc/gender.py +2 -1
  397. endoreg_db/views/misc/stats.py +141 -106
  398. endoreg_db/views/patient/__init__.py +1 -3
  399. endoreg_db/views/patient/patient.py +141 -99
  400. endoreg_db/views/patient_examination/__init__.py +5 -5
  401. endoreg_db/views/patient_examination/patient_examination.py +43 -42
  402. endoreg_db/views/patient_examination/patient_examination_create.py +10 -15
  403. endoreg_db/views/patient_examination/patient_examination_detail.py +12 -15
  404. endoreg_db/views/patient_examination/patient_examination_list.py +21 -17
  405. endoreg_db/views/patient_examination/video.py +114 -80
  406. endoreg_db/views/patient_finding/__init__.py +1 -1
  407. endoreg_db/views/patient_finding/patient_finding.py +17 -10
  408. endoreg_db/views/patient_finding/patient_finding_optimized.py +127 -95
  409. endoreg_db/views/patient_finding_classification/__init__.py +1 -1
  410. endoreg_db/views/patient_finding_classification/pfc_create.py +35 -27
  411. endoreg_db/views/report/reimport.py +1 -1
  412. endoreg_db/views/report/report_stream.py +5 -8
  413. endoreg_db/views/requirement/__init__.py +2 -1
  414. endoreg_db/views/requirement/evaluate.py +7 -9
  415. endoreg_db/views/requirement/lookup.py +2 -3
  416. endoreg_db/views/requirement/lookup_store.py +0 -1
  417. endoreg_db/views/requirement/requirement_utils.py +2 -4
  418. endoreg_db/views/stats/__init__.py +4 -4
  419. endoreg_db/views/stats/stats_views.py +152 -115
  420. endoreg_db/views/video/__init__.py +18 -27
  421. endoreg_db/views/{ai → video/ai}/__init__.py +2 -2
  422. endoreg_db/views/{ai → video/ai}/label.py +20 -16
  423. endoreg_db/views/video/correction.py +5 -6
  424. endoreg_db/views/video/reimport.py +134 -99
  425. endoreg_db/views/video/segments_crud.py +134 -44
  426. endoreg_db/views/video/video_apply_mask.py +13 -12
  427. endoreg_db/views/video/video_correction.py +2 -1
  428. endoreg_db/views/video/video_download_processed.py +15 -15
  429. endoreg_db/views/video/video_meta_stats.py +7 -6
  430. endoreg_db/views/video/video_processing_history.py +3 -2
  431. endoreg_db/views/video/video_remove_frames.py +13 -12
  432. endoreg_db/views/video/video_stream.py +110 -82
  433. {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/METADATA +9 -3
  434. {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/RECORD +436 -433
  435. endoreg_db/import_files/processing/video_processing/video_cleanup_on_error.py +0 -119
  436. endoreg_db/management/commands/import_fallback_video.py +0 -203
  437. endoreg_db/management/commands/import_video.py +0 -422
  438. endoreg_db/management/commands/import_video_with_classification.py +0 -367
  439. endoreg_db/models/media/processing_history/processing_history.py +0 -96
  440. endoreg_db/serializers/label/__init__.py +0 -7
  441. endoreg_db/serializers/label_video_segment/_lvs_create.py +0 -149
  442. endoreg_db/serializers/label_video_segment/_lvs_update.py +0 -138
  443. endoreg_db/serializers/label_video_segment/_lvs_validate.py +0 -149
  444. endoreg_db/serializers/label_video_segment/label_video_segment_annotation.py +0 -99
  445. endoreg_db/serializers/label_video_segment/label_video_segment_update.py +0 -163
  446. endoreg_db/services/__old/pdf_import.py +0 -1487
  447. endoreg_db/services/__old/video_import.py +0 -1306
  448. endoreg_db/tasks/upload_tasks.py +0 -216
  449. endoreg_db/tasks/video_ingest.py +0 -161
  450. endoreg_db/tasks/video_processing_tasks.py +0 -327
  451. endoreg_db/views/misc/translation.py +0 -182
  452. {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/WHEEL +0 -0
  453. {endoreg_db-0.8.8.9.dist-info → endoreg_db-0.8.9.10.dist-info}/licenses/LICENSE +0 -0
@@ -14,14 +14,14 @@ import logging
14
14
  # Dynamically determine the Django project path
15
15
  # previously resolved to "/home/admin/test/lx-annotate/endoreg-db" (endoreg-db project directory)
16
16
  project_path = os.environ.get(
17
- 'ENDOREG_DJANGO_PROJECT_PATH',
18
- str(Path(__file__).resolve().parent.parent.parent)
17
+ "ENDOREG_DJANGO_PROJECT_PATH", str(Path(__file__).resolve().parent.parent.parent)
19
18
  )
20
19
  sys.path.insert(0, project_path)
21
- os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dev.dev_settings')
20
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dev.dev_settings")
22
21
 
23
22
 
24
23
  import django
24
+
25
25
  django.setup()
26
26
 
27
27
  from endoreg_db.models import VideoFile
@@ -32,8 +32,9 @@ logger = logging.getLogger(__name__)
32
32
  def check_ffmpeg_available():
33
33
  """Check if FFmpeg is available for video analysis."""
34
34
  try:
35
- result = subprocess.run(['ffmpeg', '-version'],
36
- capture_output=True, text=True, timeout=10)
35
+ result = subprocess.run(
36
+ ["ffmpeg", "-version"], capture_output=True, text=True, timeout=10
37
+ )
37
38
  return result.returncode == 0
38
39
  except (subprocess.TimeoutExpired, FileNotFoundError):
39
40
  return False
@@ -44,75 +45,97 @@ def analyze_video_with_ffmpeg(video_path):
44
45
  Use FFmpeg to analyze video file integrity and get detailed information.
45
46
  """
46
47
  analysis_result = {
47
- 'file_readable': False,
48
- 'has_video_stream': False,
49
- 'has_audio_stream': False,
50
- 'duration': None,
51
- 'codec': None,
52
- 'resolution': None,
53
- 'frame_count': None,
54
- 'errors': [],
55
- 'warnings': []
48
+ "file_readable": False,
49
+ "has_video_stream": False,
50
+ "has_audio_stream": False,
51
+ "duration": None,
52
+ "codec": None,
53
+ "resolution": None,
54
+ "frame_count": None,
55
+ "errors": [],
56
+ "warnings": [],
56
57
  }
57
-
58
+
58
59
  try:
59
60
  # First, try to probe the file
60
61
  print(f"📊 Analyzing video with FFprobe: {video_path}")
61
62
  probe_cmd = [
62
- 'ffprobe', '-v', 'quiet', '-print_format', 'json',
63
- '-show_format', '-show_streams', str(video_path)
63
+ "ffprobe",
64
+ "-v",
65
+ "quiet",
66
+ "-print_format",
67
+ "json",
68
+ "-show_format",
69
+ "-show_streams",
70
+ str(video_path),
64
71
  ]
65
-
72
+
66
73
  result = subprocess.run(probe_cmd, capture_output=True, text=True, timeout=30)
67
-
74
+
68
75
  if result.returncode == 0:
69
- analysis_result['file_readable'] = True
76
+ analysis_result["file_readable"] = True
70
77
  probe_data = json.loads(result.stdout)
71
-
78
+
72
79
  # Analyze streams
73
- if 'streams' in probe_data:
74
- for stream in probe_data['streams']:
75
- if stream.get('codec_type') == 'video':
76
- analysis_result['has_video_stream'] = True
77
- analysis_result['codec'] = stream.get('codec_name')
78
- analysis_result['resolution'] = f"{stream.get('width', '?')}x{stream.get('height', '?')}"
79
- analysis_result['frame_count'] = stream.get('nb_frames')
80
- elif stream.get('codec_type') == 'audio':
81
- analysis_result['has_audio_stream'] = True
82
-
80
+ if "streams" in probe_data:
81
+ for stream in probe_data["streams"]:
82
+ if stream.get("codec_type") == "video":
83
+ analysis_result["has_video_stream"] = True
84
+ analysis_result["codec"] = stream.get("codec_name")
85
+ analysis_result["resolution"] = (
86
+ f"{stream.get('width', '?')}x{stream.get('height', '?')}"
87
+ )
88
+ analysis_result["frame_count"] = stream.get("nb_frames")
89
+ elif stream.get("codec_type") == "audio":
90
+ analysis_result["has_audio_stream"] = True
91
+
83
92
  # Get format info
84
- if 'format' in probe_data:
85
- analysis_result['duration'] = float(probe_data['format'].get('duration', 0))
93
+ if "format" in probe_data:
94
+ analysis_result["duration"] = float(
95
+ probe_data["format"].get("duration", 0)
96
+ )
86
97
  else:
87
- analysis_result['errors'].append(f"FFprobe failed: {result.stderr}")
88
-
98
+ analysis_result["errors"].append(f"FFprobe failed: {result.stderr}")
99
+
89
100
  except subprocess.TimeoutExpired:
90
- analysis_result['errors'].append("FFprobe timed out - file might be severely corrupted")
101
+ analysis_result["errors"].append(
102
+ "FFprobe timed out - file might be severely corrupted"
103
+ )
91
104
  except json.JSONDecodeError:
92
- analysis_result['errors'].append("FFprobe returned invalid JSON")
105
+ analysis_result["errors"].append("FFprobe returned invalid JSON")
93
106
  except Exception as e:
94
- analysis_result['errors'].append(f"FFprobe analysis failed: {e}")
95
-
107
+ analysis_result["errors"].append(f"FFprobe analysis failed: {e}")
108
+
96
109
  # Try to validate file integrity
97
110
  try:
98
111
  print("🔍 Testing video integrity...")
99
112
  integrity_cmd = [
100
- 'ffmpeg', '-v', 'error', '-i', str(video_path),
101
- '-f', 'null', '-', '-t', '5' # Test first 5 seconds
113
+ "ffmpeg",
114
+ "-v",
115
+ "error",
116
+ "-i",
117
+ str(video_path),
118
+ "-f",
119
+ "null",
120
+ "-",
121
+ "-t",
122
+ "5", # Test first 5 seconds
102
123
  ]
103
-
104
- result = subprocess.run(integrity_cmd, capture_output=True, text=True, timeout=30)
105
-
124
+
125
+ result = subprocess.run(
126
+ integrity_cmd, capture_output=True, text=True, timeout=30
127
+ )
128
+
106
129
  if result.returncode == 0:
107
130
  print("✅ Video integrity test passed")
108
131
  else:
109
- analysis_result['errors'].append(f"Integrity test failed: {result.stderr}")
110
-
132
+ analysis_result["errors"].append(f"Integrity test failed: {result.stderr}")
133
+
111
134
  except subprocess.TimeoutExpired:
112
- analysis_result['errors'].append("Integrity test timed out")
135
+ analysis_result["errors"].append("Integrity test timed out")
113
136
  except Exception as e:
114
- analysis_result['errors'].append(f"Integrity test failed: {e}")
115
-
137
+ analysis_result["errors"].append(f"Integrity test failed: {e}")
138
+
116
139
  return analysis_result
117
140
 
118
141
 
@@ -121,56 +144,75 @@ def test_video_streaming_compatibility(video_path):
121
144
  Test if video is compatible with web streaming (H.264 baseline profile recommended).
122
145
  """
123
146
  compatibility_result = {
124
- 'web_compatible': False,
125
- 'streaming_friendly': False,
126
- 'needs_conversion': False,
127
- 'recommendations': []
147
+ "web_compatible": False,
148
+ "streaming_friendly": False,
149
+ "needs_conversion": False,
150
+ "recommendations": [],
128
151
  }
129
-
152
+
130
153
  try:
131
154
  # Check codec and profile
132
155
  cmd = [
133
- 'ffprobe', '-v', 'quiet', '-select_streams', 'v:0',
134
- '-show_entries', 'stream=codec_name,profile,level,pix_fmt',
135
- '-of', 'csv=p=0', str(video_path)
156
+ "ffprobe",
157
+ "-v",
158
+ "quiet",
159
+ "-select_streams",
160
+ "v:0",
161
+ "-show_entries",
162
+ "stream=codec_name,profile,level,pix_fmt",
163
+ "-of",
164
+ "csv=p=0",
165
+ str(video_path),
136
166
  ]
137
-
167
+
138
168
  result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
139
-
169
+
140
170
  if result.returncode == 0:
141
- codec_info = result.stdout.strip().split(',')
171
+ codec_info = result.stdout.strip().split(",")
142
172
  if len(codec_info) >= 1:
143
173
  codec = codec_info[0]
144
-
145
- if codec == 'h264':
146
- compatibility_result['web_compatible'] = True
147
-
174
+
175
+ if codec == "h264":
176
+ compatibility_result["web_compatible"] = True
177
+
148
178
  # Check if moov atom is at the beginning (for streaming)
149
- moov_cmd = ['ffprobe', '-v', 'quiet', '-show_entries', 'format',
150
- '-of', 'csv=p=0', str(video_path)]
151
- moov_result = subprocess.run(moov_cmd, capture_output=True, text=True, timeout=10)
152
-
153
- if 'mov,mp4' in moov_result.stdout:
154
- compatibility_result['streaming_friendly'] = True
179
+ moov_cmd = [
180
+ "ffprobe",
181
+ "-v",
182
+ "quiet",
183
+ "-show_entries",
184
+ "format",
185
+ "-of",
186
+ "csv=p=0",
187
+ str(video_path),
188
+ ]
189
+ moov_result = subprocess.run(
190
+ moov_cmd, capture_output=True, text=True, timeout=10
191
+ )
192
+
193
+ if "mov,mp4" in moov_result.stdout:
194
+ compatibility_result["streaming_friendly"] = True
155
195
  else:
156
- compatibility_result['recommendations'].append(
196
+ compatibility_result["recommendations"].append(
157
197
  "Consider re-encoding with 'faststart' flag for better streaming"
158
198
  )
159
-
160
- elif codec in ['hevc', 'h265']:
161
- compatibility_result['recommendations'].append(
199
+
200
+ elif codec in ["hevc", "h265"]:
201
+ compatibility_result["recommendations"].append(
162
202
  "HEVC/H.265 codec may not be supported in all browsers"
163
203
  )
164
- compatibility_result['needs_conversion'] = True
204
+ compatibility_result["needs_conversion"] = True
165
205
  else:
166
- compatibility_result['recommendations'].append(
206
+ compatibility_result["recommendations"].append(
167
207
  f"Codec '{codec}' may not be web-compatible. Consider H.264"
168
208
  )
169
- compatibility_result['needs_conversion'] = True
170
-
209
+ compatibility_result["needs_conversion"] = True
210
+
171
211
  except Exception as e:
172
- compatibility_result['recommendations'].append(f"Could not analyze compatibility: {e}")
173
-
212
+ compatibility_result["recommendations"].append(
213
+ f"Could not analyze compatibility: {e}"
214
+ )
215
+
174
216
  return compatibility_result
175
217
 
176
218
 
@@ -179,64 +221,74 @@ def test_django_video_access(video_id):
179
221
  Test accessing the video through Django ORM and methods.
180
222
  """
181
223
  access_result = {
182
- 'orm_accessible': False,
183
- 'has_raw_file': False,
184
- 'has_processed_file': False,
185
- 'active_file_path': None,
186
- 'file_size': 0,
187
- 'errors': []
224
+ "orm_accessible": False,
225
+ "has_raw_file": False,
226
+ "has_processed_file": False,
227
+ "active_file_path": None,
228
+ "file_size": 0,
229
+ "errors": [],
188
230
  }
189
-
231
+
190
232
  try:
191
233
  video = VideoFile.objects.get(pk=video_id)
192
- access_result['orm_accessible'] = True
193
-
234
+ access_result["orm_accessible"] = True
235
+
194
236
  # Check raw file
195
- if hasattr(video, 'raw_file') and video.raw_file:
237
+ if hasattr(video, "raw_file") and video.raw_file:
196
238
  try:
197
239
  raw_path = video.raw_file.path
198
240
  if Path(raw_path).exists():
199
- access_result['has_raw_file'] = True
200
- access_result['active_file_path'] = raw_path
201
- access_result['file_size'] = Path(raw_path).stat().st_size
241
+ access_result["has_raw_file"] = True
242
+ access_result["active_file_path"] = raw_path
243
+ access_result["file_size"] = Path(raw_path).stat().st_size
202
244
  except Exception as e:
203
- access_result['errors'].append(f"Raw file access error: {e}")
204
-
245
+ access_result["errors"].append(f"Raw file access error: {e}")
246
+
205
247
  # Check processed file
206
- if hasattr(video, 'processed_file') and video.processed_file:
248
+ if hasattr(video, "processed_file") and video.processed_file:
207
249
  try:
208
250
  processed_path = video.processed_file.path
209
251
  if Path(processed_path).exists():
210
- access_result['has_processed_file'] = True
211
- if not access_result['active_file_path']:
212
- access_result['active_file_path'] = processed_path
213
- access_result['file_size'] = Path(processed_path).stat().st_size
252
+ access_result["has_processed_file"] = True
253
+ if not access_result["active_file_path"]:
254
+ access_result["active_file_path"] = processed_path
255
+ access_result["file_size"] = Path(processed_path).stat().st_size
214
256
  except Exception as e:
215
- access_result['errors'].append(f"Processed file access error: {e}")
216
-
257
+ access_result["errors"].append(f"Processed file access error: {e}")
258
+
217
259
  # Test video streaming methods
218
260
  try:
219
- if hasattr(video, 'get_active_file_path'):
261
+ if hasattr(video, "get_active_file_path"):
220
262
  active_path = video.get_active_file_path()
221
263
  if active_path and Path(active_path).exists():
222
- access_result['active_file_path'] = str(active_path)
223
- access_result['file_size'] = Path(active_path).stat().st_size
264
+ access_result["active_file_path"] = str(active_path)
265
+ access_result["file_size"] = Path(active_path).stat().st_size
224
266
  except Exception as e:
225
- access_result['errors'].append(f"Active file path method error: {e}")
226
-
267
+ access_result["errors"].append(f"Active file path method error: {e}")
268
+
227
269
  except VideoFile.DoesNotExist:
228
- access_result['errors'].append(f"Video with ID {video_id} not found in database")
270
+ access_result["errors"].append(
271
+ f"Video with ID {video_id} not found in database"
272
+ )
229
273
  except Exception as e:
230
- access_result['errors'].append(f"Django access error: {e}")
231
-
274
+ access_result["errors"].append(f"Django access error: {e}")
275
+
232
276
  return access_result
233
277
 
234
278
 
235
279
  def main():
236
280
  import argparse
237
281
 
238
- parser = argparse.ArgumentParser(description="Comprehensive video file validation script for debugging streaming issues.")
239
- parser.add_argument('video_id', nargs='?', type=int, default=5, help='ID of the video to validate (default: 5)')
282
+ parser = argparse.ArgumentParser(
283
+ description="Comprehensive video file validation script for debugging streaming issues."
284
+ )
285
+ parser.add_argument(
286
+ "video_id",
287
+ nargs="?",
288
+ type=int,
289
+ default=5,
290
+ help="ID of the video to validate (default: 5)",
291
+ )
240
292
  args = parser.parse_args()
241
293
 
242
294
  video_id = args.video_id
@@ -245,38 +297,38 @@ def main():
245
297
  print("=" * 50)
246
298
  print(f"Testing video ID: {video_id}")
247
299
  print()
248
-
300
+
249
301
  # Test Django access
250
302
  print("1️⃣ Testing Django ORM Access...")
251
303
  django_result = test_django_video_access(video_id)
252
-
253
- if django_result['orm_accessible']:
304
+
305
+ if django_result["orm_accessible"]:
254
306
  print("✅ Video found in database")
255
307
  print(f"📁 Active file path: {django_result['active_file_path']}")
256
- print(f"📏 File size: {django_result['file_size'] / (1024*1024):.1f} MB")
257
-
258
- if django_result['errors']:
259
- for error in django_result['errors']:
308
+ print(f"📏 File size: {django_result['file_size'] / (1024 * 1024):.1f} MB")
309
+
310
+ if django_result["errors"]:
311
+ for error in django_result["errors"]:
260
312
  print(f"⚠️ {error}")
261
313
  else:
262
314
  print("❌ Video not accessible through Django")
263
- for error in django_result['errors']:
315
+ for error in django_result["errors"]:
264
316
  print(f"❌ {error}")
265
317
  return
266
-
318
+
267
319
  # Get video file path for further testing
268
- video_path = django_result['active_file_path']
320
+ video_path = django_result["active_file_path"]
269
321
  if not video_path or not Path(video_path).exists():
270
322
  print("❌ No valid video file path found")
271
323
  return
272
-
324
+
273
325
  print("\n2️⃣ Testing File System Access...")
274
326
  file_path = Path(video_path)
275
327
  print(f"📁 Path: {file_path}")
276
328
  print(f"✅ File exists: {file_path.exists()}")
277
- print(f"📏 Size: {file_path.stat().st_size / (1024*1024):.1f} MB")
329
+ print(f"📏 Size: {file_path.stat().st_size / (1024 * 1024):.1f} MB")
278
330
  print(f"🔑 Readable: {os.access(file_path, os.R_OK)}")
279
-
331
+
280
332
  # Check FFmpeg availability
281
333
  print("\n3️⃣ Checking FFmpeg Availability...")
282
334
  if not check_ffmpeg_available():
@@ -285,73 +337,79 @@ def main():
285
337
  return
286
338
  else:
287
339
  print("✅ FFmpeg is available")
288
-
340
+
289
341
  # Analyze video with FFmpeg
290
342
  print("\n4️⃣ Video Analysis with FFmpeg...")
291
343
  analysis = analyze_video_with_ffmpeg(video_path)
292
-
293
- if analysis['file_readable']:
344
+
345
+ if analysis["file_readable"]:
294
346
  print("✅ File is readable by FFmpeg")
295
347
  print(f"🎥 Has video stream: {analysis['has_video_stream']}")
296
348
  print(f"🔊 Has audio stream: {analysis['has_audio_stream']}")
297
- print(f"⏱️ Duration: {analysis['duration']:.2f}s" if analysis['duration'] else "⏱️ Duration: Unknown")
349
+ print(
350
+ f"⏱️ Duration: {analysis['duration']:.2f}s"
351
+ if analysis["duration"]
352
+ else "⏱️ Duration: Unknown"
353
+ )
298
354
  print(f"🎬 Codec: {analysis['codec'] or 'Unknown'}")
299
355
  print(f"📐 Resolution: {analysis['resolution'] or 'Unknown'}")
300
356
  print(f"🖼️ Frame count: {analysis['frame_count'] or 'Unknown'}")
301
357
  else:
302
358
  print("❌ File is NOT readable by FFmpeg")
303
-
304
- if analysis['errors']:
359
+
360
+ if analysis["errors"]:
305
361
  print("\n❌ Errors found:")
306
- for error in analysis['errors']:
362
+ for error in analysis["errors"]:
307
363
  print(f" • {error}")
308
-
309
- if analysis['warnings']:
364
+
365
+ if analysis["warnings"]:
310
366
  print("\n⚠️ Warnings:")
311
- for warning in analysis['warnings']:
367
+ for warning in analysis["warnings"]:
312
368
  print(f" • {warning}")
313
-
369
+
314
370
  # Test streaming compatibility
315
371
  print("\n5️⃣ Testing Web Streaming Compatibility...")
316
372
  compatibility = test_video_streaming_compatibility(video_path)
317
-
373
+
318
374
  print(f"🌐 Web compatible: {compatibility['web_compatible']}")
319
375
  print(f"📡 Streaming friendly: {compatibility['streaming_friendly']}")
320
376
  print(f"🔄 Needs conversion: {compatibility['needs_conversion']}")
321
-
322
- if compatibility['recommendations']:
377
+
378
+ if compatibility["recommendations"]:
323
379
  print("\n💡 Recommendations:")
324
- for rec in compatibility['recommendations']:
380
+ for rec in compatibility["recommendations"]:
325
381
  print(f" • {rec}")
326
-
382
+
327
383
  # Final diagnosis
328
384
  print("\n6️⃣ DIAGNOSIS")
329
385
  print("=" * 30)
330
-
331
- if not analysis['file_readable']:
386
+
387
+ if not analysis["file_readable"]:
332
388
  print("🔴 CRITICAL: Video file is corrupted or unreadable")
333
389
  print("📋 Action: Replace or re-encode the video file")
334
- elif not analysis['has_video_stream']:
390
+ elif not analysis["has_video_stream"]:
335
391
  print("🔴 CRITICAL: No video stream found")
336
392
  print("📋 Action: Check if file is actually a video")
337
- elif not compatibility['web_compatible']:
393
+ elif not compatibility["web_compatible"]:
338
394
  print("🟡 WARNING: Video may not be web-compatible")
339
395
  print("📋 Action: Consider re-encoding to H.264")
340
- elif not compatibility['streaming_friendly']:
396
+ elif not compatibility["streaming_friendly"]:
341
397
  print("🟡 WARNING: Video not optimized for streaming")
342
398
  print("📋 Action: Re-encode with faststart flag")
343
399
  else:
344
400
  print("🟢 GOOD: Video appears to be valid and web-compatible")
345
401
  print("📋 Issue likely in Django streaming view or network connection")
346
-
402
+
347
403
  print("\n🔧 Suggested fixes for streaming issues:")
348
404
  print("1. Check Django VideoStreamView implementation")
349
405
  print("2. Verify file permissions (readable by web server)")
350
406
  print("3. Test with a different video file")
351
407
  print("4. Check browser developer tools for specific errors")
352
408
  print("5. Consider re-encoding the video:")
353
- print(f" ffmpeg -i '{video_path}' -c:v libx264 -profile:v baseline -level 3.0 -movflags faststart output.mp4")
409
+ print(
410
+ f" ffmpeg -i '{video_path}' -c:v libx264 -profile:v baseline -level 3.0 -movflags faststart output.mp4"
411
+ )
354
412
 
355
413
 
356
414
  if __name__ == "__main__":
357
- main()
415
+ main()
@@ -1,5 +1,9 @@
1
1
  from .video_splitter import split_video
2
- from .names import get_video_key, identify_video_key, get_video_key_regex_by_examination_alias
2
+ from .names import (
3
+ get_video_key,
4
+ identify_video_key,
5
+ get_video_key_regex_by_examination_alias,
6
+ )
3
7
 
4
8
  # Add necessary functions from ffmpeg_wrapper
5
9
  from .ffmpeg_wrapper import (
@@ -7,7 +11,7 @@ from .ffmpeg_wrapper import (
7
11
  assemble_video_from_frames,
8
12
  transcode_video,
9
13
  transcode_videofile_if_required,
10
- extract_frames as ffmpeg_extract_frames # Alias to avoid potential name clash if 'extract_frames' was used elsewhere directly from __init__
14
+ extract_frames as ffmpeg_extract_frames, # Alias to avoid potential name clash if 'extract_frames' was used elsewhere directly from __init__
11
15
  )
12
16
 
13
17
 
@@ -22,5 +26,5 @@ __all__ = [
22
26
  "assemble_video_from_frames",
23
27
  "transcode_video",
24
28
  "transcode_videofile_if_required",
25
- "ffmpeg_extract_frames", # Use the alias if needed
29
+ "ffmpeg_extract_frames", # Use the alias if needed
26
30
  ]