endoreg-db 0.8.8.0__py3-none-any.whl → 0.8.9.2__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 (402) hide show
  1. endoreg_db/data/__init__.py +22 -8
  2. endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +0 -1
  3. endoreg_db/data/examination/examinations/data.yaml +114 -14
  4. endoreg_db/data/examination/time-type/data.yaml +0 -3
  5. endoreg_db/data/examination_indication/endoscopy.yaml +108 -173
  6. endoreg_db/data/examination_indication_classification/endoscopy.yaml +0 -70
  7. endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +33 -37
  8. endoreg_db/data/finding/00_generic.yaml +35 -0
  9. endoreg_db/data/finding/00_generic_complication.yaml +9 -0
  10. endoreg_db/data/finding/01_gastroscopy_baseline.yaml +88 -0
  11. endoreg_db/data/finding/01_gastroscopy_observation.yaml +113 -0
  12. endoreg_db/data/finding/02_colonoscopy_baseline.yaml +53 -0
  13. endoreg_db/data/finding/02_colonoscopy_hidden.yaml +119 -0
  14. endoreg_db/data/finding/02_colonoscopy_observation.yaml +152 -0
  15. endoreg_db/data/finding_classification/00_generic.yaml +44 -0
  16. endoreg_db/data/finding_classification/00_generic_histology.yaml +28 -0
  17. endoreg_db/data/finding_classification/00_generic_lesion.yaml +52 -0
  18. endoreg_db/data/finding_classification/{colonoscopy_bowel_preparation.yaml → 02_colonoscopy_baseline.yaml} +35 -20
  19. endoreg_db/data/finding_classification/02_colonoscopy_histology.yaml +13 -0
  20. endoreg_db/data/finding_classification/02_colonoscopy_other.yaml +12 -0
  21. endoreg_db/data/finding_classification/02_colonoscopy_polyp.yaml +101 -0
  22. endoreg_db/data/finding_classification_choice/{yes_no_na.yaml → 00_generic.yaml} +5 -1
  23. endoreg_db/data/finding_classification_choice/{examination_setting_generic_types.yaml → 00_generic_baseline.yaml} +10 -2
  24. endoreg_db/data/finding_classification_choice/{complication_generic_types.yaml → 00_generic_complication.yaml} +1 -1
  25. endoreg_db/data/finding_classification_choice/{histology.yaml → 00_generic_histology.yaml} +1 -4
  26. endoreg_db/data/finding_classification_choice/00_generic_lesion.yaml +158 -0
  27. endoreg_db/data/finding_classification_choice/{bowel_preparation.yaml → 02_colonoscopy_bowel_preparation.yaml} +1 -30
  28. endoreg_db/data/{_examples/finding_classification_choice/colonoscopy_not_complete_reason.yaml → finding_classification_choice/02_colonoscopy_generic.yaml} +1 -1
  29. endoreg_db/data/finding_classification_choice/{histology_polyp.yaml → 02_colonoscopy_histology.yaml} +1 -1
  30. endoreg_db/data/{_examples/finding_classification_choice/colonoscopy_location.yaml → finding_classification_choice/02_colonoscopy_location.yaml} +23 -4
  31. endoreg_db/data/finding_classification_choice/02_colonoscopy_other.yaml +34 -0
  32. endoreg_db/data/finding_classification_choice/02_colonoscopy_polyp_advanced_imaging.yaml +76 -0
  33. endoreg_db/data/{_examples/finding_classification_choice/colon_lesion_paris.yaml → finding_classification_choice/02_colonoscopy_polyp_morphology.yaml} +26 -8
  34. endoreg_db/data/finding_classification_choice/02_colonoscopy_size.yaml +27 -0
  35. endoreg_db/data/finding_classification_type/{colonoscopy_basic.yaml → 00_generic.yaml} +18 -13
  36. endoreg_db/data/finding_classification_type/02_colonoscopy.yaml +9 -0
  37. endoreg_db/data/finding_intervention/00_generic_endoscopy.yaml +59 -0
  38. endoreg_db/data/finding_intervention/00_generic_endoscopy_ablation.yaml +44 -0
  39. endoreg_db/data/finding_intervention/00_generic_endoscopy_bleeding.yaml +55 -0
  40. endoreg_db/data/finding_intervention/00_generic_endoscopy_resection.yaml +85 -0
  41. endoreg_db/data/finding_intervention/00_generic_endoscopy_stenosis.yaml +17 -0
  42. endoreg_db/data/finding_intervention/00_generic_endoscopy_stent.yaml +9 -0
  43. endoreg_db/data/finding_intervention/01_gastroscopy.yaml +19 -0
  44. endoreg_db/data/finding_intervention/04_eus.yaml +39 -0
  45. endoreg_db/data/finding_intervention/05_ercp.yaml +3 -0
  46. endoreg_db/data/finding_type/data.yaml +8 -12
  47. endoreg_db/data/requirement/01_patient_data.yaml +93 -0
  48. endoreg_db/data/requirement_operator/new_operators.yaml +36 -0
  49. endoreg_db/data/requirement_set/01_endoscopy_generic.yaml +0 -2
  50. endoreg_db/data/requirement_set/90_coloreg.yaml +20 -8
  51. endoreg_db/exceptions.py +0 -1
  52. endoreg_db/forms/examination_form.py +1 -1
  53. endoreg_db/helpers/data_loader.py +124 -52
  54. endoreg_db/helpers/default_objects.py +116 -81
  55. endoreg_db/import_files/__init__.py +27 -0
  56. endoreg_db/import_files/context/__init__.py +7 -0
  57. endoreg_db/import_files/context/default_sensitive_meta.py +81 -0
  58. endoreg_db/import_files/context/ensure_center.py +17 -0
  59. endoreg_db/import_files/context/file_lock.py +66 -0
  60. endoreg_db/import_files/context/import_context.py +43 -0
  61. endoreg_db/import_files/context/validate_directories.py +56 -0
  62. endoreg_db/import_files/file_storage/__init__.py +15 -0
  63. endoreg_db/import_files/file_storage/create_report_file.py +76 -0
  64. endoreg_db/import_files/file_storage/create_video_file.py +75 -0
  65. endoreg_db/import_files/file_storage/sensitive_meta_storage.py +39 -0
  66. endoreg_db/import_files/file_storage/state_management.py +496 -0
  67. endoreg_db/import_files/file_storage/storage.py +36 -0
  68. endoreg_db/import_files/import_service.md +26 -0
  69. endoreg_db/import_files/processing/__init__.py +11 -0
  70. endoreg_db/import_files/processing/report_processing/report_anonymization.py +94 -0
  71. endoreg_db/import_files/processing/sensitive_meta_adapter.py +51 -0
  72. endoreg_db/import_files/processing/video_processing/video_anonymization.py +107 -0
  73. endoreg_db/import_files/pseudonymization/fake.py +52 -0
  74. endoreg_db/import_files/pseudonymization/k_anonymity.py +182 -0
  75. endoreg_db/import_files/pseudonymization/k_pseudonymity.py +128 -0
  76. endoreg_db/import_files/pseudonymization/pseudonymize.py +0 -0
  77. endoreg_db/import_files/report_import_service.py +141 -0
  78. endoreg_db/import_files/video_import_service.py +150 -0
  79. endoreg_db/management/commands/import_report.py +130 -65
  80. endoreg_db/management/commands/import_video_with_classification.py +1 -1
  81. endoreg_db/management/commands/load_ai_model_data.py +5 -5
  82. endoreg_db/management/commands/load_ai_model_label_data.py +9 -7
  83. endoreg_db/management/commands/load_base_db_data.py +5 -134
  84. endoreg_db/management/commands/load_contraindication_data.py +14 -16
  85. endoreg_db/management/commands/load_disease_classification_choices_data.py +15 -18
  86. endoreg_db/management/commands/load_disease_classification_data.py +15 -18
  87. endoreg_db/management/commands/load_disease_data.py +25 -28
  88. endoreg_db/management/commands/load_endoscope_data.py +20 -27
  89. endoreg_db/management/commands/load_event_data.py +14 -16
  90. endoreg_db/management/commands/load_examination_data.py +31 -44
  91. endoreg_db/management/commands/load_examination_indication_data.py +20 -21
  92. endoreg_db/management/commands/load_finding_data.py +52 -80
  93. endoreg_db/management/commands/load_information_source.py +21 -23
  94. endoreg_db/management/commands/load_lab_value_data.py +17 -26
  95. endoreg_db/management/commands/load_medication_data.py +13 -12
  96. endoreg_db/management/commands/load_organ_data.py +15 -19
  97. endoreg_db/management/commands/load_pdf_type_data.py +19 -18
  98. endoreg_db/management/commands/load_profession_data.py +14 -17
  99. endoreg_db/management/commands/load_qualification_data.py +20 -23
  100. endoreg_db/management/commands/load_report_reader_flag_data.py +17 -19
  101. endoreg_db/management/commands/load_requirement_data.py +14 -20
  102. endoreg_db/management/commands/load_risk_data.py +7 -6
  103. endoreg_db/management/commands/load_shift_data.py +20 -23
  104. endoreg_db/management/commands/load_tag_data.py +8 -11
  105. endoreg_db/management/commands/load_unit_data.py +17 -19
  106. endoreg_db/management/commands/start_filewatcher.py +46 -37
  107. endoreg_db/management/commands/validate_video_files.py +1 -5
  108. endoreg_db/migrations/0001_initial.py +1360 -1812
  109. endoreg_db/models/administration/person/patient/patient.py +72 -46
  110. endoreg_db/models/label/__init__.py +2 -2
  111. endoreg_db/models/label/annotation/video_segmentation_annotation.py +18 -26
  112. endoreg_db/models/label/label_video_segment/label_video_segment.py +23 -1
  113. endoreg_db/models/media/pdf/raw_pdf.py +136 -64
  114. endoreg_db/models/media/pdf/report_reader/report_reader_config.py +34 -10
  115. endoreg_db/models/media/processing_history/__init__.py +5 -0
  116. endoreg_db/models/media/processing_history/processing_history.py +96 -0
  117. endoreg_db/models/media/video/create_from_file.py +101 -31
  118. endoreg_db/models/media/video/video_file.py +125 -105
  119. endoreg_db/models/media/video/video_file_io.py +31 -26
  120. endoreg_db/models/medical/contraindication/README.md +1 -0
  121. endoreg_db/models/medical/examination/examination.py +28 -8
  122. endoreg_db/models/medical/examination/examination_indication.py +13 -79
  123. endoreg_db/models/medical/examination/examination_time.py +8 -3
  124. endoreg_db/models/medical/finding/finding.py +5 -12
  125. endoreg_db/models/medical/finding/finding_classification.py +18 -37
  126. endoreg_db/models/medical/finding/finding_intervention.py +7 -9
  127. endoreg_db/models/medical/hardware/endoscope.py +6 -0
  128. endoreg_db/models/medical/patient/medication_examples.py +5 -1
  129. endoreg_db/models/medical/patient/patient_finding.py +1 -1
  130. endoreg_db/models/metadata/pdf_meta.py +22 -10
  131. endoreg_db/models/metadata/sensitive_meta.py +3 -0
  132. endoreg_db/models/metadata/sensitive_meta_logic.py +200 -124
  133. endoreg_db/models/other/information_source.py +27 -6
  134. endoreg_db/models/report/__init__.py +0 -0
  135. endoreg_db/models/report/images.py +0 -0
  136. endoreg_db/models/report/report.py +6 -0
  137. endoreg_db/models/requirement/requirement.py +59 -399
  138. endoreg_db/models/requirement/requirement_operator.py +86 -98
  139. endoreg_db/models/state/audit_ledger.py +4 -5
  140. endoreg_db/models/state/raw_pdf.py +69 -30
  141. endoreg_db/models/state/video.py +65 -49
  142. endoreg_db/models/upload_job.py +33 -9
  143. endoreg_db/models/utils.py +27 -23
  144. endoreg_db/queries/__init__.py +3 -1
  145. endoreg_db/schemas/examination_evaluation.py +1 -1
  146. endoreg_db/serializers/__init__.py +2 -8
  147. endoreg_db/serializers/label_video_segment/label_video_segment.py +2 -29
  148. endoreg_db/serializers/meta/__init__.py +1 -6
  149. endoreg_db/serializers/misc/sensitive_patient_data.py +50 -26
  150. endoreg_db/serializers/patient_examination/patient_examination.py +3 -3
  151. endoreg_db/serializers/pdf/anony_text_validation.py +39 -23
  152. endoreg_db/serializers/video/video_file_list.py +65 -34
  153. endoreg_db/services/__old/pdf_import.py +1487 -0
  154. endoreg_db/services/__old/video_import.py +1306 -0
  155. endoreg_db/services/anonymization.py +63 -26
  156. endoreg_db/services/lookup_service.py +28 -28
  157. endoreg_db/services/lookup_store.py +2 -2
  158. endoreg_db/services/pdf_import.py +0 -1480
  159. endoreg_db/services/report_import.py +10 -0
  160. endoreg_db/services/video_import.py +6 -1165
  161. endoreg_db/tasks/upload_tasks.py +79 -70
  162. endoreg_db/tasks/video_ingest.py +8 -4
  163. endoreg_db/urls/__init__.py +0 -14
  164. endoreg_db/urls/ai.py +32 -0
  165. endoreg_db/urls/media.py +21 -24
  166. endoreg_db/utils/dataloader.py +87 -57
  167. endoreg_db/utils/paths.py +110 -46
  168. endoreg_db/utils/pipelines/Readme.md +1 -1
  169. endoreg_db/utils/requirement_operator_logic/new_operator_logic.py +97 -0
  170. endoreg_db/utils/video/ffmpeg_wrapper.py +217 -52
  171. endoreg_db/views/__init__.py +85 -173
  172. endoreg_db/views/ai/__init__.py +8 -0
  173. endoreg_db/views/ai/label.py +155 -0
  174. endoreg_db/views/anonymization/media_management.py +8 -7
  175. endoreg_db/views/anonymization/overview.py +97 -68
  176. endoreg_db/views/anonymization/validate.py +25 -21
  177. endoreg_db/views/media/__init__.py +5 -20
  178. endoreg_db/views/media/pdf_media.py +109 -65
  179. endoreg_db/views/media/sensitive_metadata.py +163 -148
  180. endoreg_db/views/meta/__init__.py +0 -8
  181. endoreg_db/views/misc/__init__.py +1 -7
  182. endoreg_db/views/misc/upload_views.py +94 -93
  183. endoreg_db/views/report/__init__.py +7 -0
  184. endoreg_db/views/{pdf → report}/reimport.py +45 -24
  185. endoreg_db/views/{pdf/pdf_stream.py → report/report_stream.py} +40 -32
  186. endoreg_db/views/requirement/lookup_store.py +22 -90
  187. endoreg_db/views/video/__init__.py +23 -22
  188. endoreg_db/views/video/correction.py +201 -172
  189. endoreg_db/views/video/reimport.py +1 -1
  190. endoreg_db/views/{media/video_segments.py → video/segments_crud.py} +75 -37
  191. endoreg_db/views/video/{video_meta.py → video_meta_stats.py} +2 -2
  192. endoreg_db/views/video/video_stream.py +7 -8
  193. {endoreg_db-0.8.8.0.dist-info → endoreg_db-0.8.9.2.dist-info}/METADATA +2 -2
  194. {endoreg_db-0.8.8.0.dist-info → endoreg_db-0.8.9.2.dist-info}/RECORD +217 -335
  195. {endoreg_db-0.8.8.0.dist-info → endoreg_db-0.8.9.2.dist-info}/WHEEL +1 -1
  196. endoreg_db/data/_examples/disease.yaml +0 -55
  197. endoreg_db/data/_examples/disease_classification.yaml +0 -13
  198. endoreg_db/data/_examples/disease_classification_choice.yaml +0 -62
  199. endoreg_db/data/_examples/event.yaml +0 -64
  200. endoreg_db/data/_examples/examination.yaml +0 -72
  201. endoreg_db/data/_examples/finding/anatomy_colon.yaml +0 -128
  202. endoreg_db/data/_examples/finding/colonoscopy.yaml +0 -40
  203. endoreg_db/data/_examples/finding/colonoscopy_bowel_prep.yaml +0 -56
  204. endoreg_db/data/_examples/finding/complication.yaml +0 -16
  205. endoreg_db/data/_examples/finding/data.yaml +0 -105
  206. endoreg_db/data/_examples/finding/examination_setting.yaml +0 -16
  207. endoreg_db/data/_examples/finding/medication_related.yaml +0 -18
  208. endoreg_db/data/_examples/finding/outcome.yaml +0 -12
  209. endoreg_db/data/_examples/finding_classification/colonoscopy_bowel_preparation.yaml +0 -68
  210. endoreg_db/data/_examples/finding_classification/colonoscopy_jnet.yaml +0 -22
  211. endoreg_db/data/_examples/finding_classification/colonoscopy_kudo.yaml +0 -25
  212. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
  213. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
  214. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_size.yaml +0 -68
  215. endoreg_db/data/_examples/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
  216. endoreg_db/data/_examples/finding_classification/colonoscopy_location.yaml +0 -80
  217. endoreg_db/data/_examples/finding_classification/colonoscopy_lst.yaml +0 -21
  218. endoreg_db/data/_examples/finding_classification/colonoscopy_nice.yaml +0 -20
  219. endoreg_db/data/_examples/finding_classification/colonoscopy_paris.yaml +0 -26
  220. endoreg_db/data/_examples/finding_classification/colonoscopy_sano.yaml +0 -22
  221. endoreg_db/data/_examples/finding_classification/colonoscopy_summary.yaml +0 -53
  222. endoreg_db/data/_examples/finding_classification/complication_generic.yaml +0 -25
  223. endoreg_db/data/_examples/finding_classification/examination_setting_generic.yaml +0 -40
  224. endoreg_db/data/_examples/finding_classification/histology_colo.yaml +0 -51
  225. endoreg_db/data/_examples/finding_classification/intervention_required.yaml +0 -26
  226. endoreg_db/data/_examples/finding_classification/medication_related.yaml +0 -23
  227. endoreg_db/data/_examples/finding_classification/visualized.yaml +0 -33
  228. endoreg_db/data/_examples/finding_classification_choice/bowel_preparation.yaml +0 -78
  229. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
  230. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
  231. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
  232. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_lst.yaml +0 -15
  233. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_nice.yaml +0 -17
  234. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
  235. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_sano.yaml +0 -14
  236. endoreg_db/data/_examples/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
  237. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_size.yaml +0 -82
  238. endoreg_db/data/_examples/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
  239. endoreg_db/data/_examples/finding_classification_choice/complication_generic_types.yaml +0 -15
  240. endoreg_db/data/_examples/finding_classification_choice/examination_setting_generic_types.yaml +0 -15
  241. endoreg_db/data/_examples/finding_classification_choice/histology.yaml +0 -24
  242. endoreg_db/data/_examples/finding_classification_choice/histology_polyp.yaml +0 -20
  243. endoreg_db/data/_examples/finding_classification_choice/outcome.yaml +0 -19
  244. endoreg_db/data/_examples/finding_classification_choice/yes_no_na.yaml +0 -11
  245. endoreg_db/data/_examples/finding_classification_type/colonoscopy_basic.yaml +0 -48
  246. endoreg_db/data/_examples/finding_intervention/endoscopy.yaml +0 -43
  247. endoreg_db/data/_examples/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
  248. endoreg_db/data/_examples/finding_intervention/endoscopy_egd.yaml +0 -128
  249. endoreg_db/data/_examples/finding_intervention/endoscopy_ercp.yaml +0 -32
  250. endoreg_db/data/_examples/finding_intervention/endoscopy_eus_lower.yaml +0 -9
  251. endoreg_db/data/_examples/finding_intervention/endoscopy_eus_upper.yaml +0 -36
  252. endoreg_db/data/_examples/finding_intervention_type/endoscopy.yaml +0 -15
  253. endoreg_db/data/_examples/finding_type/data.yaml +0 -43
  254. endoreg_db/data/_examples/requirement/age.yaml +0 -26
  255. endoreg_db/data/_examples/requirement/gender.yaml +0 -25
  256. endoreg_db/data/_examples/requirement_set/01_endoscopy_generic.yaml +0 -48
  257. endoreg_db/data/_examples/requirement_set/colonoscopy_austria_screening.yaml +0 -57
  258. endoreg_db/data/_examples/requirement_set/endoscopy_bleeding_risk.yaml +0 -52
  259. endoreg_db/data/_examples/yaml_examples.xlsx +0 -0
  260. endoreg_db/data/finding/anatomy_colon.yaml +0 -128
  261. endoreg_db/data/finding/colonoscopy.yaml +0 -40
  262. endoreg_db/data/finding/colonoscopy_bowel_prep.yaml +0 -56
  263. endoreg_db/data/finding/complication.yaml +0 -16
  264. endoreg_db/data/finding/data.yaml +0 -105
  265. endoreg_db/data/finding/examination_setting.yaml +0 -16
  266. endoreg_db/data/finding/medication_related.yaml +0 -18
  267. endoreg_db/data/finding/outcome.yaml +0 -12
  268. endoreg_db/data/finding_classification/colonoscopy_jnet.yaml +0 -22
  269. endoreg_db/data/finding_classification/colonoscopy_kudo.yaml +0 -25
  270. endoreg_db/data/finding_classification/colonoscopy_lesion_circularity.yaml +0 -20
  271. endoreg_db/data/finding_classification/colonoscopy_lesion_planarity.yaml +0 -24
  272. endoreg_db/data/finding_classification/colonoscopy_lesion_size.yaml +0 -38
  273. endoreg_db/data/finding_classification/colonoscopy_lesion_surface.yaml +0 -20
  274. endoreg_db/data/finding_classification/colonoscopy_location.yaml +0 -49
  275. endoreg_db/data/finding_classification/colonoscopy_lst.yaml +0 -21
  276. endoreg_db/data/finding_classification/colonoscopy_nice.yaml +0 -20
  277. endoreg_db/data/finding_classification/colonoscopy_paris.yaml +0 -26
  278. endoreg_db/data/finding_classification/colonoscopy_sano.yaml +0 -22
  279. endoreg_db/data/finding_classification/colonoscopy_summary.yaml +0 -53
  280. endoreg_db/data/finding_classification/complication_generic.yaml +0 -25
  281. endoreg_db/data/finding_classification/examination_setting_generic.yaml +0 -40
  282. endoreg_db/data/finding_classification/histology_colo.yaml +0 -43
  283. endoreg_db/data/finding_classification/intervention_required.yaml +0 -26
  284. endoreg_db/data/finding_classification/medication_related.yaml +0 -23
  285. endoreg_db/data/finding_classification/visualized.yaml +0 -33
  286. endoreg_db/data/finding_classification_choice/colon_lesion_circularity_default.yaml +0 -32
  287. endoreg_db/data/finding_classification_choice/colon_lesion_jnet.yaml +0 -15
  288. endoreg_db/data/finding_classification_choice/colon_lesion_kudo.yaml +0 -23
  289. endoreg_db/data/finding_classification_choice/colon_lesion_lst.yaml +0 -15
  290. endoreg_db/data/finding_classification_choice/colon_lesion_nice.yaml +0 -17
  291. endoreg_db/data/finding_classification_choice/colon_lesion_paris.yaml +0 -57
  292. endoreg_db/data/finding_classification_choice/colon_lesion_planarity_default.yaml +0 -49
  293. endoreg_db/data/finding_classification_choice/colon_lesion_sano.yaml +0 -14
  294. endoreg_db/data/finding_classification_choice/colon_lesion_surface_intact_default.yaml +0 -36
  295. endoreg_db/data/finding_classification_choice/colonoscopy_location.yaml +0 -229
  296. endoreg_db/data/finding_classification_choice/colonoscopy_not_complete_reason.yaml +0 -19
  297. endoreg_db/data/finding_classification_choice/colonoscopy_size.yaml +0 -82
  298. endoreg_db/data/finding_classification_choice/colonoscopy_summary_worst_finding.yaml +0 -15
  299. endoreg_db/data/finding_classification_choice/outcome.yaml +0 -19
  300. endoreg_db/data/finding_intervention/endoscopy.yaml +0 -43
  301. endoreg_db/data/finding_intervention/endoscopy_colonoscopy.yaml +0 -168
  302. endoreg_db/data/finding_intervention/endoscopy_egd.yaml +0 -128
  303. endoreg_db/data/finding_intervention/endoscopy_ercp.yaml +0 -32
  304. endoreg_db/data/finding_intervention/endoscopy_eus_lower.yaml +0 -9
  305. endoreg_db/data/finding_intervention/endoscopy_eus_upper.yaml +0 -36
  306. endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +0 -79
  307. endoreg_db/data/requirement/age.yaml +0 -26
  308. endoreg_db/data/requirement/colonoscopy_baseline_austria.yaml +0 -45
  309. endoreg_db/data/requirement/disease_cardiovascular.yaml +0 -79
  310. endoreg_db/data/requirement/disease_classification_choice_cardiovascular.yaml +0 -41
  311. endoreg_db/data/requirement/disease_hepatology.yaml +0 -12
  312. endoreg_db/data/requirement/disease_misc.yaml +0 -12
  313. endoreg_db/data/requirement/disease_renal.yaml +0 -96
  314. endoreg_db/data/requirement/endoscopy_bleeding_risk.yaml +0 -59
  315. endoreg_db/data/requirement/event_cardiology.yaml +0 -251
  316. endoreg_db/data/requirement/event_requirements.yaml +0 -145
  317. endoreg_db/data/requirement/finding_colon_polyp.yaml +0 -50
  318. endoreg_db/data/requirement/gender.yaml +0 -25
  319. endoreg_db/data/requirement/lab_value.yaml +0 -441
  320. endoreg_db/data/requirement/medication.yaml +0 -93
  321. endoreg_db/data/requirement_operator/age.yaml +0 -13
  322. endoreg_db/data/requirement_operator/lab_operators.yaml +0 -129
  323. endoreg_db/data/requirement_operator/model_operators.yaml +0 -96
  324. endoreg_db/management/commands/init_default_ai_model.py +0 -112
  325. endoreg_db/management/commands/reset_celery_schedule.py +0 -9
  326. endoreg_db/management/commands/validate_video.py +0 -204
  327. endoreg_db/migrations/0002_requirementset_depends_on.py +0 -18
  328. endoreg_db/migrations/_old/0001_initial.py +0 -1857
  329. endoreg_db/migrations/_old/0002_add_video_correction_models.py +0 -52
  330. endoreg_db/migrations/_old/0003_add_center_display_name.py +0 -30
  331. endoreg_db/migrations/_old/0004_employee_city_employee_post_code_employee_street_and_more.py +0 -68
  332. endoreg_db/migrations/_old/0004_remove_casetemplate_rules_and_more.py +0 -77
  333. endoreg_db/migrations/_old/0005_merge_20251111_1003.py +0 -14
  334. endoreg_db/migrations/_old/0006_sensitivemeta_anonymized_text_and_more.py +0 -68
  335. endoreg_db/migrations/_old/0007_remove_rule_attribute_dtype_remove_rule_rule_type_and_more.py +0 -89
  336. endoreg_db/migrations/_old/0008_remove_event_event_classification_and_more.py +0 -27
  337. endoreg_db/migrations/_old/0009_alter_modelmeta_options_and_more.py +0 -21
  338. endoreg_db/renames.yml +0 -8
  339. endoreg_db/serializers/_old/raw_pdf_meta_validation.py +0 -223
  340. endoreg_db/serializers/_old/raw_video_meta_validation.py +0 -179
  341. endoreg_db/serializers/_old/video.py +0 -71
  342. endoreg_db/serializers/meta/pdf_file_meta_extraction.py +0 -115
  343. endoreg_db/serializers/meta/report_meta.py +0 -53
  344. endoreg_db/serializers/report/__init__.py +0 -9
  345. endoreg_db/serializers/report/mixins.py +0 -45
  346. endoreg_db/serializers/report/report.py +0 -105
  347. endoreg_db/serializers/report/report_list.py +0 -22
  348. endoreg_db/serializers/report/secure_file_url.py +0 -26
  349. endoreg_db/services/requirements_object.py +0 -147
  350. endoreg_db/services/storage_aware_video_processor.py +0 -370
  351. endoreg_db/urls/files.py +0 -6
  352. endoreg_db/urls/label_video_segment_validate.py +0 -33
  353. endoreg_db/urls/label_video_segments.py +0 -46
  354. endoreg_db/views/label/__init__.py +0 -5
  355. endoreg_db/views/label/label.py +0 -15
  356. endoreg_db/views/label_video_segment/__init__.py +0 -16
  357. endoreg_db/views/label_video_segment/create_lvs_from_annotation.py +0 -44
  358. endoreg_db/views/label_video_segment/get_lvs_by_name_and_video.py +0 -50
  359. endoreg_db/views/label_video_segment/label_video_segment.py +0 -77
  360. endoreg_db/views/label_video_segment/label_video_segment_by_label.py +0 -174
  361. endoreg_db/views/label_video_segment/label_video_segment_detail.py +0 -73
  362. endoreg_db/views/label_video_segment/update_lvs_from_annotation.py +0 -46
  363. endoreg_db/views/label_video_segment/validate.py +0 -226
  364. endoreg_db/views/media/segments.py +0 -71
  365. endoreg_db/views/meta/available_files_list.py +0 -146
  366. endoreg_db/views/meta/report_meta.py +0 -53
  367. endoreg_db/views/meta/sensitive_meta_detail.py +0 -85
  368. endoreg_db/views/misc/secure_file_serving_view.py +0 -80
  369. endoreg_db/views/misc/secure_file_url_view.py +0 -84
  370. endoreg_db/views/misc/secure_url_validate.py +0 -79
  371. endoreg_db/views/patient_examination/DEPRECATED_video_backup.py +0 -164
  372. endoreg_db/views/patient_finding_location/__init__.py +0 -5
  373. endoreg_db/views/patient_finding_location/pfl_create.py +0 -70
  374. endoreg_db/views/patient_finding_morphology/__init__.py +0 -5
  375. endoreg_db/views/patient_finding_morphology/pfm_create.py +0 -70
  376. endoreg_db/views/pdf/__init__.py +0 -8
  377. endoreg_db/views/video/segmentation.py +0 -274
  378. endoreg_db/views/video/task_status.py +0 -49
  379. endoreg_db/views/video/timeline.py +0 -46
  380. endoreg_db/views/video/video_analyze.py +0 -52
  381. /endoreg_db/data/requirement/{colon_polyp_intervention.yaml → old/colon_polyp_intervention.yaml} +0 -0
  382. /endoreg_db/data/{_examples/requirement → requirement/old}/colonoscopy_baseline_austria.yaml +0 -0
  383. /endoreg_db/data/requirement/{coloreg_colon_polyp.yaml → old/coloreg_colon_polyp.yaml} +0 -0
  384. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_cardiovascular.yaml +0 -0
  385. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_classification_choice_cardiovascular.yaml +0 -0
  386. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_hepatology.yaml +0 -0
  387. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_misc.yaml +0 -0
  388. /endoreg_db/data/{_examples/requirement → requirement/old}/disease_renal.yaml +0 -0
  389. /endoreg_db/data/{_examples/requirement → requirement/old}/endoscopy_bleeding_risk.yaml +0 -0
  390. /endoreg_db/data/{_examples/requirement → requirement/old}/event_cardiology.yaml +0 -0
  391. /endoreg_db/data/{_examples/requirement → requirement/old}/event_requirements.yaml +0 -0
  392. /endoreg_db/data/{_examples/requirement → requirement/old}/finding_colon_polyp.yaml +0 -0
  393. /endoreg_db/{urls/sensitive_meta.py → data/requirement/old/gender.yaml} +0 -0
  394. /endoreg_db/data/{_examples/requirement → requirement/old}/lab_value.yaml +0 -0
  395. /endoreg_db/data/{_examples/requirement → requirement/old}/medication.yaml +0 -0
  396. /endoreg_db/data/{_examples/requirement_operator → requirement_operator/_old}/age.yaml +0 -0
  397. /endoreg_db/data/{_examples/requirement_operator → requirement_operator/_old}/lab_operators.yaml +0 -0
  398. /endoreg_db/data/{_examples/requirement_operator → requirement_operator/_old}/model_operators.yaml +0 -0
  399. /endoreg_db/{views/pdf/pdf_stream_views.py → import_files/pseudonymization/__init__.py} +0 -0
  400. /endoreg_db/utils/requirement_operator_logic/{lab_value_operators.py → _old/lab_value_operators.py} +0 -0
  401. /endoreg_db/utils/requirement_operator_logic/{model_evaluators.py → _old/model_evaluators.py} +0 -0
  402. {endoreg_db-0.8.8.0.dist-info → endoreg_db-0.8.9.2.dist-info}/licenses/LICENSE +0 -0
@@ -31,7 +31,11 @@ def _resolve_ffmpeg_executable() -> Optional[str]:
31
31
  try:
32
32
  from django.conf import settings
33
33
 
34
- env_candidates.extend(getattr(settings, attr) for attr in ("FFMPEG_EXECUTABLE", "FFMPEG_BINARY", "FFMPEG_PATH") if hasattr(settings, attr))
34
+ env_candidates.extend(
35
+ getattr(settings, attr)
36
+ for attr in ("FFMPEG_EXECUTABLE", "FFMPEG_BINARY", "FFMPEG_PATH")
37
+ if hasattr(settings, attr)
38
+ )
35
39
  except Exception:
36
40
  # Django might not be configured for every consumer
37
41
  pass
@@ -83,9 +87,24 @@ def _detect_nvenc_support() -> bool:
83
87
  """
84
88
  try:
85
89
  # Test NVENC availability with a minimal command (minimum size for NVENC)
86
- cmd = ["ffmpeg", "-f", "lavfi", "-i", "testsrc=duration=1:size=256x256:rate=1", "-c:v", "h264_nvenc", "-preset", "p1", "-f", "null", "-"]
90
+ cmd = [
91
+ "ffmpeg",
92
+ "-f",
93
+ "lavfi",
94
+ "-i",
95
+ "testsrc=duration=1:size=256x256:rate=1",
96
+ "-c:v",
97
+ "h264_nvenc",
98
+ "-preset",
99
+ "p1",
100
+ "-f",
101
+ "null",
102
+ "-",
103
+ ]
87
104
 
88
- result = subprocess.run(cmd, capture_output=True, text=True, timeout=15, check=False)
105
+ result = subprocess.run(
106
+ cmd, capture_output=True, text=True, timeout=15, check=False
107
+ )
89
108
 
90
109
  if result.returncode == 0:
91
110
  logger.debug("NVENC h264 encoding test successful")
@@ -141,7 +160,11 @@ def _get_preferred_encoder() -> Dict[str, str]:
141
160
  return _preferred_encoder
142
161
 
143
162
 
144
- def _build_encoder_args(quality_mode: str = "balanced", fallback: bool = False, custom_crf: Optional[int] = None) -> Tuple[List[str], str]:
163
+ def _build_encoder_args(
164
+ quality_mode: str = "balanced",
165
+ fallback: bool = False,
166
+ custom_crf: Optional[int] = None,
167
+ ) -> Tuple[List[str], str]:
145
168
  """
146
169
  Build encoder command arguments based on available hardware and quality requirements.
147
170
 
@@ -207,7 +230,16 @@ def _build_encoder_args(quality_mode: str = "balanced", fallback: bool = False,
207
230
  if custom_crf is not None:
208
231
  quality = str(custom_crf)
209
232
 
210
- return ["-c:v", encoder["name"], encoder["preset_param"], preset, encoder["quality_param"], quality, "-profile:v", "high"], encoder["type"]
233
+ return [
234
+ "-c:v",
235
+ encoder["name"],
236
+ encoder["preset_param"],
237
+ preset,
238
+ encoder["quality_param"],
239
+ quality,
240
+ "-profile:v",
241
+ "high",
242
+ ], encoder["type"]
211
243
 
212
244
 
213
245
  def is_ffmpeg_available() -> bool:
@@ -231,7 +263,9 @@ def check_ffmpeg_availability():
231
263
  True if FFmpeg is available.
232
264
  """
233
265
  if not is_ffmpeg_available():
234
- error_msg = "FFmpeg is not available. Please install it and ensure it's in your PATH."
266
+ error_msg = (
267
+ "FFmpeg is not available. Please install it and ensure it's in your PATH."
268
+ )
235
269
  logger.error(error_msg)
236
270
  raise FileNotFoundError(error_msg)
237
271
  # logger.info("FFmpeg is available.") # Caller can log if needed
@@ -292,9 +326,15 @@ def assemble_video_from_frames( # Renamed from assemble_video
292
326
  if first_frame is None:
293
327
  raise IOError(f"Could not read first frame: {frame_paths[0]}")
294
328
  height, width, _ = first_frame.shape
295
- logger.info("Determined video dimensions from first frame: %dx%d", width, height)
329
+ logger.info(
330
+ "Determined video dimensions from first frame: %dx%d", width, height
331
+ )
296
332
  except Exception as e:
297
- logger.error("Error reading first frame to determine dimensions: %s", e, exc_info=True)
333
+ logger.error(
334
+ "Error reading first frame to determine dimensions: %s",
335
+ e,
336
+ exc_info=True,
337
+ )
298
338
  return None
299
339
 
300
340
  fourcc = cv2.VideoWriter_fourcc(*"mp4v")
@@ -305,7 +345,9 @@ def assemble_video_from_frames( # Renamed from assemble_video
305
345
  logger.error("Could not open video writer for path: %s", output_path)
306
346
  return None
307
347
 
308
- logger.info("Assembling video %s from %d frames...", output_path.name, len(frame_paths))
348
+ logger.info(
349
+ "Assembling video %s from %d frames...", output_path.name, len(frame_paths)
350
+ )
309
351
  try:
310
352
  for frame_path in tqdm(frame_paths, desc=f"Assembling {output_path.name}"):
311
353
  frame = cv2.imread(str(frame_path))
@@ -314,7 +356,9 @@ def assemble_video_from_frames( # Renamed from assemble_video
314
356
  continue
315
357
  # Ensure frame dimensions match - resize if necessary (or log error)
316
358
  if frame.shape[1] != width or frame.shape[0] != height:
317
- logger.warning(f"Frame {frame_path} has dimensions {frame.shape[1]}x{frame.shape[0]}, expected {width}x{height}. Resizing.")
359
+ logger.warning(
360
+ f"Frame {frame_path} has dimensions {frame.shape[1]}x{frame.shape[0]}, expected {width}x{height}. Resizing."
361
+ )
318
362
  frame = cv2.resize(frame, (width, height))
319
363
  video_writer.write(frame)
320
364
  finally:
@@ -364,7 +408,9 @@ def transcode_video(
364
408
  if codec == "auto" or preset == "auto":
365
409
  if force_cpu:
366
410
  # Force CPU encoding
367
- encoder_args, encoder_type = _build_encoder_args(quality_mode, fallback=False, custom_crf=crf)
411
+ encoder_args, encoder_type = _build_encoder_args(
412
+ quality_mode, fallback=False, custom_crf=crf
413
+ )
368
414
  # Override to use CPU encoder
369
415
  encoder_args[1] = "libx264" # Replace encoder name
370
416
  encoder_args[3] = "medium" if preset == "auto" else preset # Replace preset
@@ -372,7 +418,9 @@ def transcode_video(
372
418
  encoder_args[5] = str(crf) # Replace quality value
373
419
  else:
374
420
  # Use automatic hardware detection
375
- encoder_args, encoder_type = _build_encoder_args(quality_mode, fallback=False, custom_crf=crf)
421
+ encoder_args, encoder_type = _build_encoder_args(
422
+ quality_mode, fallback=False, custom_crf=crf
423
+ )
376
424
  else:
377
425
  # Manual codec/preset specification (backward compatibility)
378
426
  encoder_args = [
@@ -402,11 +450,18 @@ def transcode_video(
402
450
  command.extend(extra_args)
403
451
  command.append(str(output_path))
404
452
 
405
- logger.info("Starting transcoding: %s -> %s (using %s)", input_path.name, output_path.name, encoder_type)
453
+ logger.info(
454
+ "Starting transcoding: %s -> %s (using %s)",
455
+ input_path.name,
456
+ output_path.name,
457
+ encoder_type,
458
+ )
406
459
  logger.debug("FFmpeg command: %s", " ".join(command))
407
460
 
408
461
  try:
409
- process = subprocess.Popen(command, stderr=subprocess.PIPE, text=True, universal_newlines=True)
462
+ process = subprocess.Popen(
463
+ command, stderr=subprocess.PIPE, text=True, universal_newlines=True
464
+ )
410
465
 
411
466
  # Progress reporting and error handling
412
467
  stderr_output = ""
@@ -420,32 +475,56 @@ def transcode_video(
420
475
  logger.info("Transcoding finished successfully: %s", output_path)
421
476
  return output_path
422
477
  else:
423
- logger.error("FFmpeg transcoding failed for %s with return code %d.", input_path.name, process.returncode)
478
+ logger.error(
479
+ "FFmpeg transcoding failed for %s with return code %d.",
480
+ input_path.name,
481
+ process.returncode,
482
+ )
424
483
  logger.error("FFmpeg stderr:\n%s", stderr_output)
425
484
 
426
485
  # Try fallback to CPU if NVENC failed
427
486
  if encoder_type == "nvenc" and not force_cpu:
428
487
  logger.warning("NVENC transcoding failed, trying CPU fallback...")
429
- return _transcode_video_fallback(input_path, output_path, audio_codec, audio_bitrate, extra_args, quality_mode, crf)
488
+ return _transcode_video_fallback(
489
+ input_path,
490
+ output_path,
491
+ audio_codec,
492
+ audio_bitrate,
493
+ extra_args,
494
+ quality_mode,
495
+ crf,
496
+ )
430
497
 
431
498
  # Clean up potentially corrupted output file
432
499
  if output_path.exists():
433
500
  try:
434
501
  output_path.unlink()
435
502
  except OSError as e:
436
- logger.error("Failed to delete incomplete output file %s: %s", output_path, e)
503
+ logger.error(
504
+ "Failed to delete incomplete output file %s: %s", output_path, e
505
+ )
437
506
  return None
438
507
 
439
508
  except FileNotFoundError:
440
- logger.error("ffmpeg command not found. Ensure FFmpeg is installed and in the system's PATH.")
509
+ logger.error(
510
+ "ffmpeg command not found. Ensure FFmpeg is installed and in the system's PATH."
511
+ )
441
512
  return None
442
513
  except Exception as e:
443
- logger.error("Error during transcoding of %s: %s", input_path.name, e, exc_info=True)
514
+ logger.error(
515
+ "Error during transcoding of %s: %s", input_path.name, e, exc_info=True
516
+ )
444
517
  return None
445
518
 
446
519
 
447
520
  def _transcode_video_fallback(
448
- input_path: Path, output_path: Path, audio_codec: str, audio_bitrate: str, extra_args: Optional[List[str]], quality_mode: str, custom_crf: Optional[int]
521
+ input_path: Path,
522
+ output_path: Path,
523
+ audio_codec: str,
524
+ audio_bitrate: str,
525
+ extra_args: Optional[List[str]],
526
+ quality_mode: str,
527
+ custom_crf: Optional[int],
449
528
  ) -> Optional[Path]:
450
529
  """
451
530
  Fallback transcoding using CPU encoding.
@@ -464,7 +543,9 @@ def _transcode_video_fallback(
464
543
  """
465
544
  try:
466
545
  # Build CPU encoder arguments
467
- encoder_args, _ = _build_encoder_args(quality_mode, fallback=True, custom_crf=custom_crf)
546
+ encoder_args, _ = _build_encoder_args(
547
+ quality_mode, fallback=True, custom_crf=custom_crf
548
+ )
468
549
  # Force CPU encoder
469
550
  encoder_args[1] = "libx264"
470
551
 
@@ -484,10 +565,14 @@ def _transcode_video_fallback(
484
565
  command.extend(extra_args)
485
566
  command.append(str(output_path))
486
567
 
487
- logger.info("CPU fallback transcoding: %s -> %s", input_path.name, output_path.name)
568
+ logger.info(
569
+ "CPU fallback transcoding: %s -> %s", input_path.name, output_path.name
570
+ )
488
571
  logger.debug("Fallback FFmpeg command: %s", " ".join(command))
489
572
 
490
- process = subprocess.Popen(command, stderr=subprocess.PIPE, text=True, universal_newlines=True)
573
+ process = subprocess.Popen(
574
+ command, stderr=subprocess.PIPE, text=True, universal_newlines=True
575
+ )
491
576
  stderr_output = ""
492
577
  if process.stderr:
493
578
  for line in process.stderr:
@@ -511,7 +596,9 @@ def _transcode_video_fallback(
511
596
  logger.debug("FFmpeg command: %s", " ".join(command))
512
597
 
513
598
  try:
514
- process = subprocess.Popen(command, stderr=subprocess.PIPE, text=True, universal_newlines=True)
599
+ process = subprocess.Popen(
600
+ command, stderr=subprocess.PIPE, text=True, universal_newlines=True
601
+ )
515
602
 
516
603
  # Optional: Progress reporting (can be complex to parse ffmpeg output reliably)
517
604
  # For simplicity, just wait and check the return code
@@ -528,21 +615,31 @@ def _transcode_video_fallback(
528
615
  logger.info("Transcoding finished successfully: %s", output_path)
529
616
  return output_path
530
617
  else:
531
- logger.error("FFmpeg transcoding failed for %s with return code %d.", input_path.name, process.returncode)
618
+ logger.error(
619
+ "FFmpeg transcoding failed for %s with return code %d.",
620
+ input_path.name,
621
+ process.returncode,
622
+ )
532
623
  logger.error("FFmpeg stderr:\n%s", stderr_output)
533
624
  # Clean up potentially corrupted output file
534
625
  if output_path.exists():
535
626
  try:
536
627
  output_path.unlink()
537
628
  except OSError as e:
538
- logger.error("Failed to delete incomplete output file %s: %s", output_path, e)
629
+ logger.error(
630
+ "Failed to delete incomplete output file %s: %s", output_path, e
631
+ )
539
632
  return None
540
633
 
541
634
  except FileNotFoundError:
542
- logger.error("ffmpeg command not found. Ensure FFmpeg is installed and in the system's PATH.")
635
+ logger.error(
636
+ "ffmpeg command not found. Ensure FFmpeg is installed and in the system's PATH."
637
+ )
543
638
  return None
544
639
  except Exception as e:
545
- logger.error("Error during transcoding of %s: %s", input_path.name, e, exc_info=True)
640
+ logger.error(
641
+ "Error during transcoding of %s: %s", input_path.name, e, exc_info=True
642
+ )
546
643
  return None
547
644
 
548
645
 
@@ -561,10 +658,15 @@ def transcode_videofile_if_required(
561
658
  """
562
659
  stream_info = get_stream_info(input_path)
563
660
  if not stream_info or "streams" not in stream_info:
564
- logger.error("Could not get stream info for %s to check if transcoding is required.", input_path)
661
+ logger.error(
662
+ "Could not get stream info for %s to check if transcoding is required.",
663
+ input_path,
664
+ )
565
665
  return None
566
666
 
567
- video_stream = next((s for s in stream_info["streams"] if s.get("codec_type") == "video"), None)
667
+ video_stream = next(
668
+ (s for s in stream_info["streams"] if s.get("codec_type") == "video"), None
669
+ )
568
670
 
569
671
  if not video_stream:
570
672
  logger.error("No video stream found in %s.", input_path)
@@ -573,7 +675,9 @@ def transcode_videofile_if_required(
573
675
  codec_name = video_stream.get("codec_name")
574
676
  pixel_format = video_stream.get("pix_fmt")
575
677
  # Check color range as well, default is usually 'tv' (limited)
576
- color_range = video_stream.get("color_range", "tv") # Default to tv if not specified
678
+ color_range = video_stream.get(
679
+ "color_range", "tv"
680
+ ) # Default to tv if not specified
577
681
 
578
682
  needs_transcoding = False
579
683
  transcode_reason = []
@@ -583,16 +687,25 @@ def transcode_videofile_if_required(
583
687
  transcode_reason.append(reason)
584
688
  needs_transcoding = True
585
689
  # Check both pixel format and color range for yuv420p
586
- if pixel_format != required_pixel_format or (pixel_format == "yuv420p" and color_range != "pc"):
690
+ if pixel_format != required_pixel_format or (
691
+ pixel_format == "yuv420p" and color_range != "pc"
692
+ ):
587
693
  reason = f"Pixel format/color range mismatch (pix_fmt: {pixel_format}, color_range: {color_range} != {required_pixel_format} with color_range=pc)"
588
694
  logger.info("%s for %s. Transcoding required.", reason, input_path.name)
589
695
  transcode_reason.append(reason)
590
696
  needs_transcoding = True
591
697
 
592
698
  if needs_transcoding:
593
- logger.info("Transcoding %s to %s due to: %s", input_path.name, output_path.name, "; ".join(transcode_reason))
699
+ logger.info(
700
+ "Transcoding %s to %s due to: %s",
701
+ input_path.name,
702
+ output_path.name,
703
+ "; ".join(transcode_reason),
704
+ )
594
705
  # Ensure codec and pixel format are set in options if not already present
595
- transcode_options.setdefault("codec", "libx264" if required_codec == "h264" else required_codec)
706
+ transcode_options.setdefault(
707
+ "codec", "libx264" if required_codec == "h264" else required_codec
708
+ )
596
709
  transcode_options.setdefault("extra_args", [])
597
710
 
598
711
  # Ensure pixel format and color range are correctly set in extra_args
@@ -604,11 +717,17 @@ def transcode_videofile_if_required(
604
717
  try:
605
718
  pix_fmt_index = extra_args.index("-pix_fmt")
606
719
  if extra_args[pix_fmt_index + 1] != required_pixel_format:
607
- logger.warning("Overriding existing -pix_fmt '%s' with '%s'", extra_args[pix_fmt_index + 1], required_pixel_format)
720
+ logger.warning(
721
+ "Overriding existing -pix_fmt '%s' with '%s'",
722
+ extra_args[pix_fmt_index + 1],
723
+ required_pixel_format,
724
+ )
608
725
  extra_args[pix_fmt_index + 1] = required_pixel_format
609
726
  except (ValueError, IndexError):
610
727
  # Should not happen if '-pix_fmt' is in extra_args, but handle defensively
611
- logger.error("Error processing existing -pix_fmt argument. Appending required format.")
728
+ logger.error(
729
+ "Error processing existing -pix_fmt argument. Appending required format."
730
+ )
612
731
  extra_args.extend(["-pix_fmt", required_pixel_format])
613
732
 
614
733
  if "-color_range" not in extra_args:
@@ -619,16 +738,24 @@ def transcode_videofile_if_required(
619
738
  try:
620
739
  color_range_index = extra_args.index("-color_range")
621
740
  if extra_args[color_range_index + 1] != "pc":
622
- logger.warning("Overriding existing -color_range '%s' with 'pc'", extra_args[color_range_index + 1])
741
+ logger.warning(
742
+ "Overriding existing -color_range '%s' with 'pc'",
743
+ extra_args[color_range_index + 1],
744
+ )
623
745
  extra_args[color_range_index + 1] = "pc"
624
746
  except (ValueError, IndexError):
625
- logger.error("Error processing existing -color_range argument. Appending 'pc'.")
747
+ logger.error(
748
+ "Error processing existing -color_range argument. Appending 'pc'."
749
+ )
626
750
  extra_args.extend(["-color_range", "pc"])
627
751
 
628
752
  return transcode_video(input_path, output_path, **transcode_options)
629
753
  else:
630
754
  logger.info(
631
- "Video %s already meets requirements (%s, %s, color_range=pc). No transcoding needed.", input_path.name, required_codec, required_pixel_format
755
+ "Video %s already meets requirements (%s, %s, color_range=pc). No transcoding needed.",
756
+ input_path.name,
757
+ required_codec,
758
+ required_pixel_format,
632
759
  )
633
760
  # If no transcoding is needed, should we copy/link or just return the original path?
634
761
  # For simplicity, let's assume the caller handles the file location.
@@ -638,15 +765,27 @@ def transcode_videofile_if_required(
638
765
  try:
639
766
  output_path.parent.mkdir(parents=True, exist_ok=True)
640
767
  shutil.copy2(input_path, output_path)
641
- logger.info("Copied %s to %s as it met requirements.", input_path.name, output_path.name)
768
+ logger.info(
769
+ "Copied %s to %s as it met requirements.",
770
+ input_path.name,
771
+ output_path.name,
772
+ )
642
773
  return output_path
643
774
  except Exception as e:
644
- logger.error("Failed to copy %s to %s: %s", input_path.name, output_path.name, e)
775
+ logger.error(
776
+ "Failed to copy %s to %s: %s", input_path.name, output_path.name, e
777
+ )
645
778
  return None
646
779
  return input_path # Return original path if no copy needed
647
780
 
648
781
 
649
- def extract_frames(video_path: Path, output_dir: Path, quality: int, ext: str = "jpg", fps: Optional[float] = None) -> List[Path]:
782
+ def extract_frames(
783
+ video_path: Path,
784
+ output_dir: Path,
785
+ quality: int,
786
+ ext: str = "jpg",
787
+ fps: Optional[float] = None,
788
+ ) -> List[Path]:
650
789
  """
651
790
  Extracts frames from a video file using FFmpeg.
652
791
 
@@ -702,7 +841,9 @@ def extract_frames(video_path: Path, output_dir: Path, quality: int, ext: str =
702
841
  # Return empty list on error as frames were likely not created correctly
703
842
  return []
704
843
  except Exception as e:
705
- logger.error("An unexpected error occurred during FFmpeg execution: %s", e, exc_info=True)
844
+ logger.error(
845
+ "An unexpected error occurred during FFmpeg execution: %s", e, exc_info=True
846
+ )
706
847
  return []
707
848
 
708
849
  # Collect paths of extracted frames
@@ -743,7 +884,11 @@ def extract_frame_range(
743
884
  RuntimeError: If FFmpeg fails to extract the requested frames.
744
885
  """
745
886
  if start_frame >= end_frame:
746
- logger.warning("extract_frame_range called with start_frame (%d) >= end_frame (%d). No frames to extract.", start_frame, end_frame)
887
+ logger.warning(
888
+ "extract_frame_range called with start_frame (%d) >= end_frame (%d). No frames to extract.",
889
+ start_frame,
890
+ end_frame,
891
+ )
747
892
  return []
748
893
 
749
894
  ffmpeg_executable = _resolve_ffmpeg_executable()
@@ -790,18 +935,30 @@ def extract_frame_range(
790
935
  logger.error("FFmpeg stderr:\n%s", e.stderr)
791
936
  logger.error("FFmpeg stdout:\n%s", e.stdout)
792
937
  # Clean up potentially partially created files in the target directory within the expected range
793
- logger.warning("Attempting cleanup of potentially incomplete frames in %s", output_dir)
938
+ logger.warning(
939
+ "Attempting cleanup of potentially incomplete frames in %s", output_dir
940
+ )
794
941
  for i in range(start_frame, end_frame):
795
942
  potential_file = output_dir / f"frame_{i:07d}.{ext}"
796
943
  if potential_file.exists():
797
944
  try:
798
945
  potential_file.unlink()
799
946
  except OSError as unlink_err:
800
- logger.error("Failed to delete potential frame %s during cleanup: %s", potential_file, unlink_err)
801
- raise RuntimeError(f"FFmpeg frame range extraction failed for {video_path}") from e
947
+ logger.error(
948
+ "Failed to delete potential frame %s during cleanup: %s",
949
+ potential_file,
950
+ unlink_err,
951
+ )
952
+ raise RuntimeError(
953
+ f"FFmpeg frame range extraction failed for {video_path}"
954
+ ) from e
802
955
  except Exception as e:
803
- logger.error("An unexpected error occurred during FFmpeg execution: %s", e, exc_info=True)
804
- raise RuntimeError(f"Unexpected error during FFmpeg frame range extraction for {video_path}") from e
956
+ logger.error(
957
+ "An unexpected error occurred during FFmpeg execution: %s", e, exc_info=True
958
+ )
959
+ raise RuntimeError(
960
+ f"Unexpected error during FFmpeg frame range extraction for {video_path}"
961
+ ) from e
805
962
 
806
963
  # Collect paths of extracted frames matching the pattern and expected range
807
964
  # FFmpeg might create files outside the exact range depending on version/flags,
@@ -813,9 +970,17 @@ def extract_frame_range(
813
970
  extracted_files.append(frame_file)
814
971
  else:
815
972
  # This might happen if ffmpeg fails silently for some frames or if the video ends early.
816
- logger.warning("Expected frame file %s not found after extraction.", frame_file)
817
-
818
- logger.info("Found %d extracted frame files in range [%d, %d) for video %s.", len(extracted_files), start_frame, end_frame, video_path.name)
973
+ logger.warning(
974
+ "Expected frame file %s not found after extraction.", frame_file
975
+ )
976
+
977
+ logger.info(
978
+ "Found %d extracted frame files in range [%d, %d) for video %s.",
979
+ len(extracted_files),
980
+ start_frame,
981
+ end_frame,
982
+ video_path.name,
983
+ )
819
984
  return extracted_files
820
985
 
821
986