@camera.ui/server 0.0.15 → 0.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/dist/interface/{@tanstack.B2I9xtA-.0.0.15.js → @tanstack.Y8LHKTFF.0.0.17.js} +1 -1
  2. package/dist/interface/{@vee-validate.DWN48z-b.0.0.15.js → @vee-validate.BcG8e5-Z.0.0.17.js} +1 -1
  3. package/dist/interface/{@vueform.DKPuos4k.0.0.15.js → @vueform.Cnqje5-g.0.0.17.js} +1 -1
  4. package/dist/interface/{@vueuse.Co4EnWOQ.0.0.15.js → @vueuse.CxdA24o0.0.0.17.js} +1 -1
  5. package/dist/interface/Account.K0D29-KE.0.0.17.js +1 -0
  6. package/dist/interface/{Adminpanel.BhbCmzrT.0.0.15.js → Adminpanel.CaLBYPHc.0.0.17.js} +2 -2
  7. package/dist/interface/{Appearance.CwONb7W2.0.0.15.js → Appearance.-L_mn_-o.0.0.17.js} +1 -1
  8. package/dist/interface/{Backup.yqywczET.0.0.15.js → Backup.DjU1SUNp.0.0.17.js} +1 -1
  9. package/dist/interface/{Camera.rR0r1OyZ.0.0.15.js → Camera.BgoyeEmQ.0.0.17.js} +1 -1
  10. package/dist/interface/Cameras.CTzvFhZB.0.0.17.js +1 -0
  11. package/dist/interface/{Camview.BatKTHU_.0.0.15.js → Camview.AIHZOcpe.0.0.17.js} +1 -1
  12. package/dist/interface/Config.Dwreik6Q.0.0.17.js +1 -0
  13. package/dist/interface/{Console.B2cDWN7X.0.0.15.js → Console.65ILbQYd.0.0.17.js} +1 -1
  14. package/dist/interface/FirstSteps.CLRJ9qAX.0.0.17.js +1 -0
  15. package/dist/interface/{NewCamera.DLnkhjgo.0.0.15.js → NewCamera.C3vbU4C7.0.0.17.js} +1 -1
  16. package/dist/interface/Plugin.B5hYYBYQ.0.0.17.js +1 -0
  17. package/dist/interface/{Plugins.Bf_8zTwV.0.0.15.js → Plugins.CfRQtEq_.0.0.17.js} +1 -1
  18. package/dist/interface/Recordings.BbFFnSvi.0.0.17.js +1 -0
  19. package/dist/interface/Recordings.BfuhtdIj.0.0.17.js +1 -0
  20. package/dist/interface/{Settings.D72CuJ6O.0.0.15.js → Settings.BdOXqaEX.0.0.17.js} +1 -1
  21. package/dist/interface/System.ysu799BZ.0.0.17.js +4 -0
  22. package/dist/interface/User.D7asFmwE.0.0.17.js +1 -0
  23. package/dist/interface/{VConfigEditor.vue_vue_type_script_setup_true_lang.ZwQQjICd.0.0.15.js → VConfigEditor.vue_vue_type_script_setup_true_lang.BAxsYS8n.0.0.17.js} +2 -2
  24. package/dist/interface/{VConsole.DDTNhqOU.0.0.15.js → VConsole.C7xGb1ES.0.0.17.js} +1 -1
  25. package/dist/interface/VPlayer.Dhm7j4pg.0.0.17.js +1 -0
  26. package/dist/interface/{VPluginCard.CB7NkPU_.0.0.15.js → VPluginCard.Drmi3fPn.0.0.17.js} +1 -1
  27. package/dist/interface/{ace-builds.A-C6i9nQ.0.0.15.js → ace-builds.BwzeyovQ.0.0.17.js} +1 -1
  28. package/dist/interface/assets/{Account.0.0.15.2KfYXKTQ.css → Account.0.0.17.BCEftDNE.css} +1 -1
  29. package/dist/interface/assets/{Cameras.0.0.15.D7bnvH42.css → Cameras.0.0.17.Djx0F2MM.css} +1 -1
  30. package/dist/interface/assets/{Camview.0.0.15.cgjDTjXy.css → Camview.0.0.17.Ce_V-Nxj.css} +1 -1
  31. package/dist/interface/assets/{Config.0.0.15.BQJF6s_V.css → Config.0.0.17.k4QpWumg.css} +1 -1
  32. package/dist/interface/assets/FirstSteps.0.0.17.27JF_jaE.css +1 -0
  33. package/dist/interface/assets/{Plugin.0.0.15.BGZE7hpr.css → Plugin.0.0.17.CY2rlLw0.css} +1 -1
  34. package/dist/interface/assets/User.0.0.17.DAaNwzw2.css +1 -0
  35. package/dist/interface/assets/{VPlayer.0.0.15.CzZme_fu.css → VPlayer.0.0.17.CY8lPcC-.css} +1 -1
  36. package/dist/interface/assets/{main.0.0.15.DYbE3rQA.css → main.0.0.17.CkZIZCwa.css} +1 -1
  37. package/dist/interface/axios.CpM4fnec.0.0.17.js +6 -0
  38. package/dist/interface/{dnd-core.B8stXCD4.0.0.15.js → dnd-core.BE3BG1Ef.0.0.17.js} +1 -1
  39. package/dist/interface/{draggabilly.ev1pKJ7p.0.0.15.js → draggabilly.lOopoogm.0.0.17.js} +1 -1
  40. package/dist/interface/{engine.io-client.0boOmuXx.0.0.15.js → engine.io-client.D9WQML-S.0.0.17.js} +1 -1
  41. package/dist/interface/{ev-emitter.CyasprkB.0.0.15.js → ev-emitter.DS-zFO5E.0.0.17.js} +1 -1
  42. package/dist/interface/{fast-deep-equal.AHTVU8UN.0.0.15.js → fast-deep-equal.BEv36PJS.0.0.17.js} +1 -1
  43. package/dist/interface/{highlight.js.DHnzQuqA.0.0.15.js → highlight.js.7wLgKNe8.0.0.17.js} +1 -1
  44. package/dist/interface/index.html +33 -33
  45. package/dist/interface/{linkify-it.BRUkUrZL.0.0.15.js → linkify-it.D8o-3IGu.0.0.17.js} +1 -1
  46. package/dist/interface/main.tEGILaMo.0.0.17.js +9 -0
  47. package/dist/interface/manifest.webmanifest +1 -1
  48. package/dist/interface/{markdown-it.2TL-gV6o.0.0.15.js → markdown-it.B4HcXc4c.0.0.17.js} +1 -1
  49. package/dist/interface/{nprogress.jtDdNYD4.0.0.15.js → nprogress.YYjE43ko.0.0.17.js} +1 -1
  50. package/dist/interface/{pinia.CJpkm-vG.0.0.15.js → pinia.BN10dGtz.0.0.17.js} +1 -1
  51. package/dist/interface/{plugins.C0VE3BWq.0.0.15.js → plugins.DGem6WnK.0.0.17.js} +1 -1
  52. package/dist/interface/{qrcode.lWedcgdn.0.0.15.js → qrcode.D-tn4nkj.0.0.17.js} +1 -1
  53. package/dist/interface/{react-dnd-touch-backend.CcgNHwJq.0.0.15.js → react-dnd-touch-backend.BYa4rNzf.0.0.17.js} +1 -1
  54. package/dist/interface/{rxjs.Cl-cCUwx.0.0.15.js → rxjs.DfibtzOq.0.0.17.js} +1 -1
  55. package/dist/interface/{socket.io-client.BC7T0S5P.0.0.15.js → socket.io-client.C_uPgwFs.0.0.17.js} +1 -1
  56. package/dist/interface/{socket.io-parser.DXZBuaSn.0.0.15.js → socket.io-parser.BCv62i4g.0.0.17.js} +1 -1
  57. package/dist/interface/sw.js +1 -1
  58. package/dist/interface/system.QcA_yDW7.0.0.17.js +1 -0
  59. package/dist/interface/{ui.DfPZU-TI.0.0.15.js → ui.CsoNsn0g.0.0.17.js} +1 -1
  60. package/dist/interface/{unidragger.DUKIdJYW.0.0.15.js → unidragger.CE1ihPjj.0.0.17.js} +1 -1
  61. package/dist/interface/{v-calendar.BRsEtqcH.0.0.15.js → v-calendar.uhLzWnBK.0.0.17.js} +1 -1
  62. package/dist/interface/{vee-validate.BA6ddPlX.0.0.15.js → vee-validate.Dks-nw4k.0.0.17.js} +1 -1
  63. package/dist/interface/{vue-i18n.CSqZ9DAQ.0.0.15.js → vue-i18n.C41_xexi.0.0.17.js} +1 -1
  64. package/dist/interface/{vue-inline-svg.Cvue3xa2.0.0.15.js → vue-inline-svg.BKM1fqUr.0.0.17.js} +1 -1
  65. package/dist/interface/{vue-router.B-YJWOHm.0.0.15.js → vue-router.BPduPoYE.0.0.17.js} +1 -1
  66. package/dist/interface/{vue3-apexcharts.DMh8wxia.0.0.15.js → vue3-apexcharts.CUMFs3zS.0.0.17.js} +1 -1
  67. package/dist/interface/{vue3-dnd.C47AfXqJ.0.0.15.js → vue3-dnd.BNLgSXFo.0.0.17.js} +1 -1
  68. package/dist/interface/{vue3-toastify.CeXovHOf.0.0.15.js → vue3-toastify.D4rGDrYT.0.0.17.js} +1 -1
  69. package/dist/interface/{vuetify.CBWGmYdo.0.0.15.js → vuetify.C_gaTn8T.0.0.17.js} +1 -1
  70. package/dist/server/bin/cameraui.d.ts +4 -0
  71. package/dist/server/bin/cameraui.js +47 -33
  72. package/dist/server/bin/cameraui.js.map +1 -1
  73. package/dist/server/bin/installer/darwin.d.ts +4 -0
  74. package/dist/server/bin/installer/darwin.js +37 -29
  75. package/dist/server/bin/installer/darwin.js.map +1 -1
  76. package/dist/server/bin/installer/freebsd.d.ts +4 -5
  77. package/dist/server/bin/installer/freebsd.js +23 -33
  78. package/dist/server/bin/installer/freebsd.js.map +1 -1
  79. package/dist/server/bin/installer/linux.d.ts +7 -0
  80. package/dist/server/bin/installer/linux.js +53 -27
  81. package/dist/server/bin/installer/linux.js.map +1 -1
  82. package/dist/server/bin/installer/win32.d.ts +4 -0
  83. package/dist/server/bin/installer/win32.js +21 -14
  84. package/dist/server/bin/installer/win32.js.map +1 -1
  85. package/dist/server/package.json +4 -4
  86. package/dist/server/src/api/controllers/backup.controller.js +2 -2
  87. package/dist/server/src/api/controllers/backup.controller.js.map +1 -1
  88. package/dist/server/src/api/controllers/plugins.controller.js +42 -40
  89. package/dist/server/src/api/controllers/plugins.controller.js.map +1 -1
  90. package/dist/server/src/api/controllers/system.controller.d.ts +3 -2
  91. package/dist/server/src/api/controllers/system.controller.js +19 -21
  92. package/dist/server/src/api/controllers/system.controller.js.map +1 -1
  93. package/dist/server/src/api/controllers/users.controller.js +12 -1
  94. package/dist/server/src/api/controllers/users.controller.js.map +1 -1
  95. package/dist/server/src/api/database/index.d.ts +0 -2
  96. package/dist/server/src/api/database/index.js +5 -14
  97. package/dist/server/src/api/database/index.js.map +1 -1
  98. package/dist/server/src/api/database/types.d.ts +7 -2
  99. package/dist/server/src/api/plugins/system.plugin.js +1 -4
  100. package/dist/server/src/api/plugins/system.plugin.js.map +1 -1
  101. package/dist/server/src/api/routes/system.routes.js +2 -2
  102. package/dist/server/src/api/routes/system.routes.js.map +1 -1
  103. package/dist/server/src/api/schemas/cameras.schema.d.ts +15 -15
  104. package/dist/server/src/api/schemas/cameras.schema.js +2 -2
  105. package/dist/server/src/api/schemas/cameras.schema.js.map +1 -1
  106. package/dist/server/src/api/schemas/go2rtc.schema.d.ts +14 -14
  107. package/dist/server/src/api/schemas/users.schema.d.ts +2 -2
  108. package/dist/server/src/api/schemas/users.schema.js +4 -15
  109. package/dist/server/src/api/schemas/users.schema.js.map +1 -1
  110. package/dist/server/src/api/services/backup.service.js +16 -15
  111. package/dist/server/src/api/services/backup.service.js.map +1 -1
  112. package/dist/server/src/api/services/cameras.service.js +10 -2
  113. package/dist/server/src/api/services/cameras.service.js.map +1 -1
  114. package/dist/server/src/api/utils/cert.d.ts +1 -1
  115. package/dist/server/src/api/utils/cert.js +14 -14
  116. package/dist/server/src/api/utils/cert.js.map +1 -1
  117. package/dist/server/src/api/utils/moveFiles.js +6 -5
  118. package/dist/server/src/api/utils/moveFiles.js.map +1 -1
  119. package/dist/server/src/api/websocket/nsp/logs.js +5 -4
  120. package/dist/server/src/api/websocket/nsp/logs.js.map +1 -1
  121. package/dist/server/src/api/websocket/nsp/server.js +3 -2
  122. package/dist/server/src/api/websocket/nsp/server.js.map +1 -1
  123. package/dist/server/src/camera/index.js +2 -0
  124. package/dist/server/src/camera/index.js.map +1 -1
  125. package/dist/server/src/camera/iou.d.ts +2 -0
  126. package/dist/server/src/camera/iou.js +53 -0
  127. package/dist/server/src/camera/iou.js.map +1 -0
  128. package/dist/server/src/camera/streaming/peer-connection.d.ts +3 -1
  129. package/dist/server/src/camera/streaming/peer-connection.js +12 -7
  130. package/dist/server/src/camera/streaming/peer-connection.js.map +1 -1
  131. package/dist/server/src/camera/streaming/webrtc-connection.d.ts +2 -0
  132. package/dist/server/src/camera/streaming/webrtc-connection.js +28 -10
  133. package/dist/server/src/camera/streaming/webrtc-connection.js.map +1 -1
  134. package/dist/server/src/camera/types.d.ts +2 -1
  135. package/dist/server/src/camera/types.js.map +1 -1
  136. package/dist/server/src/main.js +8 -4
  137. package/dist/server/src/main.js.map +1 -1
  138. package/dist/server/src/nats/server.js +4 -3
  139. package/dist/server/src/nats/server.js.map +1 -1
  140. package/dist/server/src/plugins/index.js +12 -11
  141. package/dist/server/src/plugins/index.js.map +1 -1
  142. package/dist/server/src/plugins/plugin.js +6 -4
  143. package/dist/server/src/plugins/plugin.js.map +1 -1
  144. package/dist/server/src/plugins/worker.d.ts +1 -0
  145. package/dist/server/src/plugins/worker.js +24 -16
  146. package/dist/server/src/plugins/worker.js.map +1 -1
  147. package/dist/server/src/polyglot/node/decoder/child.js +16 -10
  148. package/dist/server/src/polyglot/node/decoder/child.js.map +1 -1
  149. package/dist/server/src/polyglot/node/decoder/imageUtils.js +2 -2
  150. package/dist/server/src/polyglot/node/decoder/imageUtils.js.map +1 -1
  151. package/dist/server/src/polyglot/node/plugins/cameraStorage.d.ts +3 -3
  152. package/dist/server/src/polyglot/node/plugins/cameraStorage.js +7 -21
  153. package/dist/server/src/polyglot/node/plugins/cameraStorage.js.map +1 -1
  154. package/dist/server/src/polyglot/node/plugins/child.d.ts +1 -0
  155. package/dist/server/src/polyglot/node/plugins/child.js +18 -5
  156. package/dist/server/src/polyglot/node/plugins/child.js.map +1 -1
  157. package/dist/server/src/polyglot/node/plugins/configService.d.ts +1 -1
  158. package/dist/server/src/polyglot/node/plugins/configService.js +5 -5
  159. package/dist/server/src/polyglot/node/plugins/configService.js.map +1 -1
  160. package/dist/server/src/polyglot/node/plugins/pluginApi.d.ts +3 -2
  161. package/dist/server/src/polyglot/node/plugins/pluginApi.js +3 -3
  162. package/dist/server/src/polyglot/node/plugins/pluginApi.js.map +1 -1
  163. package/dist/server/src/polyglot/node/plugins/proxy/cameraDevice.d.ts +4 -4
  164. package/dist/server/src/polyglot/node/plugins/proxy/cameraDevice.js +55 -46
  165. package/dist/server/src/polyglot/node/plugins/proxy/cameraDevice.js.map +1 -1
  166. package/dist/server/src/polyglot/node/plugins/storageController.d.ts +3 -1
  167. package/dist/server/src/polyglot/node/plugins/storageController.js +4 -2
  168. package/dist/server/src/polyglot/node/plugins/storageController.js.map +1 -1
  169. package/dist/server/src/polyglot/python/camera/iou.py +80 -0
  170. package/dist/server/src/polyglot/python/camera_ui_types/__init__.py +15 -9
  171. package/dist/server/src/polyglot/python/decoder/child.py +25 -16
  172. package/dist/server/src/polyglot/python/plugins/camera_storage.py +12 -62
  173. package/dist/server/src/polyglot/python/plugins/child.py +59 -23
  174. package/dist/server/src/polyglot/python/plugins/config_service.py +8 -1
  175. package/dist/server/src/polyglot/python/plugins/plugin_api.py +5 -1
  176. package/dist/server/src/polyglot/python/plugins/proxy/camera_device.py +88 -53
  177. package/dist/server/src/polyglot/python/plugins/proxy/core_manager.py +8 -8
  178. package/dist/server/src/polyglot/python/plugins/storage_controller.py +5 -3
  179. package/dist/server/src/polyglot/python/plugins/typings.py +6 -0
  180. package/dist/server/src/polyglot/python/utilities/json_lmdb.py +19 -0
  181. package/dist/server/src/polyglot/python/utilities/subscriptions.py +6 -4
  182. package/dist/server/src/polyglot/python/utilities/utils.py +63 -38
  183. package/dist/server/src/services/config/index.js +32 -21
  184. package/dist/server/src/services/config/index.js.map +1 -1
  185. package/dist/server/src/utils/npm.js +3 -3
  186. package/dist/server/src/utils/npm.js.map +1 -1
  187. package/dist/server/src/utils/pythonInstaller.js +16 -14
  188. package/dist/server/src/utils/pythonInstaller.js.map +1 -1
  189. package/package.json +4 -4
  190. package/dist/interface/Account.DTO3ooh3.0.0.15.js +0 -1
  191. package/dist/interface/Cameras.G9WAma5x.0.0.15.js +0 -1
  192. package/dist/interface/Config.CsvpXqyb.0.0.15.js +0 -1
  193. package/dist/interface/FirstSteps.ukPFDoeG.0.0.15.js +0 -1
  194. package/dist/interface/Plugin.N1q6ZCIP.0.0.15.js +0 -1
  195. package/dist/interface/Recordings.Bsbb82FW.0.0.15.js +0 -1
  196. package/dist/interface/Recordings.UbjwH1iF.0.0.15.js +0 -1
  197. package/dist/interface/System.XRKGIwr_.0.0.15.js +0 -4
  198. package/dist/interface/User.DzMhZQTR.0.0.15.js +0 -1
  199. package/dist/interface/VPlayer.B3iRkLXd.0.0.15.js +0 -1
  200. package/dist/interface/assets/FirstSteps.0.0.15.DFSydMqk.css +0 -1
  201. package/dist/interface/assets/User.0.0.15.CXUSYt8i.css +0 -1
  202. package/dist/interface/axios.BI2i94Vb.0.0.15.js +0 -6
  203. package/dist/interface/main.b1KIH7xr.0.0.15.js +0 -9
  204. package/dist/interface/system.Ddiy-UaE.0.0.15.js +0 -1
  205. /package/dist/interface/{@babel.l0sNRNKZ.0.0.15.js → @babel.l0sNRNKZ.0.0.17.js} +0 -0
  206. /package/dist/interface/{@intlify.YW_pt133.0.0.15.js → @intlify.YW_pt133.0.0.17.js} +0 -0
  207. /package/dist/interface/{@mdi.jq8isxax.0.0.15.js → @mdi.jq8isxax.0.0.17.js} +0 -0
  208. /package/dist/interface/{@popperjs.BQBsAJpH.0.0.15.js → @popperjs.BQBsAJpH.0.0.17.js} +0 -0
  209. /package/dist/interface/{@react-dnd.CcwRs9xb.0.0.15.js → @react-dnd.CcwRs9xb.0.0.17.js} +0 -0
  210. /package/dist/interface/{@socket.io.Dkula2eQ.0.0.15.js → @socket.io.Dkula2eQ.0.0.17.js} +0 -0
  211. /package/dist/interface/{@vue.CIFymae3.0.0.15.js → @vue.CIFymae3.0.0.17.js} +0 -0
  212. /package/dist/interface/{@xterm.CQtBFDn2.0.0.15.js → @xterm.Cq_3w6CG.0.0.17.js} +0 -0
  213. /package/dist/interface/assets/{@vueform.0.0.15.h7tNX9p6.css → @vueform.0.0.17.h7tNX9p6.css} +0 -0
  214. /package/dist/interface/assets/{@xterm.0.0.15.CGrrDQr5.css → @xterm.0.0.17.CGrrDQr5.css} +0 -0
  215. /package/dist/interface/assets/{Adminpanel.0.0.15.A2JXV1Ib.css → Adminpanel.0.0.17.A2JXV1Ib.css} +0 -0
  216. /package/dist/interface/assets/{Backup.0.0.15.BIwaSlv3.css → Backup.0.0.17.BIwaSlv3.css} +0 -0
  217. /package/dist/interface/assets/{Camera.0.0.15.BDtUJ-lA.css → Camera.0.0.17.BDtUJ-lA.css} +0 -0
  218. /package/dist/interface/assets/{Console.0.0.15.DWrfRWs9.css → Console.0.0.17.DWrfRWs9.css} +0 -0
  219. /package/dist/interface/assets/{NewCamera.0.0.15.CMzSwwHn.css → NewCamera.0.0.17.CMzSwwHn.css} +0 -0
  220. /package/dist/interface/assets/{Plugins.0.0.15.Cwu0aGUO.css → Plugins.0.0.17.Cwu0aGUO.css} +0 -0
  221. /package/dist/interface/assets/{Settings.0.0.15.DTxcLhIY.css → Settings.0.0.17.DTxcLhIY.css} +0 -0
  222. /package/dist/interface/assets/{VConsole.0.0.15.BZT1WyS-.css → VConsole.0.0.17.BZT1WyS-.css} +0 -0
  223. /package/dist/interface/assets/{VPluginCard.0.0.15.C2OqX7DJ.css → VPluginCard.0.0.17.C2OqX7DJ.css} +0 -0
  224. /package/dist/interface/assets/{highlight.0.0.15.DgoK_Xib.css → highlight.0.0.17.DgoK_Xib.css} +0 -0
  225. /package/dist/interface/assets/{logo-256.0.0.15.BCQk9H1-.png → logo-256.0.0.17.BCQk9H1-.png} +0 -0
  226. /package/dist/interface/assets/{logo-512.0.0.15.DLKVOU2S.png → logo-512.0.0.17.DLKVOU2S.png} +0 -0
  227. /package/dist/interface/assets/{logo.0.0.15.DmEiRk0z.png → logo.0.0.17.DmEiRk0z.png} +0 -0
  228. /package/dist/interface/assets/{mode-json.0.0.15.Br7xisR1.js → mode-json.0.0.17.Br7xisR1.js} +0 -0
  229. /package/dist/interface/assets/{mode-yaml.0.0.15.CIYL8U3d.js → mode-yaml.0.0.17.CIYL8U3d.js} +0 -0
  230. /package/dist/interface/assets/{v-calendar.0.0.15.CtSuDYZU.css → v-calendar.0.0.17.CtSuDYZU.css} +0 -0
  231. /package/dist/interface/assets/{vue3-toastify.0.0.15.DTY1DMRs.css → vue3-toastify.0.0.17.DTY1DMRs.css} +0 -0
  232. /package/dist/interface/assets/{vuetify.0.0.15.DPyVfAPv.css → vuetify.0.0.17.DPyVfAPv.css} +0 -0
  233. /package/dist/interface/{compare-versions.DqEOhma6.0.0.15.js → compare-versions.DqEOhma6.0.0.17.js} +0 -0
  234. /package/dist/interface/{dijkstrajs.D_NXgYpA.0.0.15.js → dijkstrajs.D_NXgYpA.0.0.17.js} +0 -0
  235. /package/dist/interface/{engine.io-parser.BiEtp6m2.0.0.15.js → engine.io-parser.BiEtp6m2.0.0.17.js} +0 -0
  236. /package/dist/interface/{entities.C20TfXL6.0.0.15.js → entities.C20TfXL6.0.0.17.js} +0 -0
  237. /package/dist/interface/{get-size.D1dS-IaP.0.0.15.js → get-size.D1dS-IaP.0.0.17.js} +0 -0
  238. /package/dist/interface/{mdurl.k9Sl0PQj.0.0.15.js → mdurl.k9Sl0PQj.0.0.17.js} +0 -0
  239. /package/dist/interface/{punycode.js.Dj65hjkv.0.0.15.js → punycode.js.Dj65hjkv.0.0.17.js} +0 -0
  240. /package/dist/interface/{react-dnd-html5-backend.1HQjlkwI.0.0.15.js → react-dnd-html5-backend.1HQjlkwI.0.0.17.js} +0 -0
  241. /package/dist/interface/{redux.CuxFRhX_.0.0.15.js → redux.CuxFRhX_.0.0.17.js} +0 -0
  242. /package/dist/interface/{tslib.9k7AwCpt.0.0.15.js → tslib.9k7AwCpt.0.0.17.js} +0 -0
  243. /package/dist/interface/{uc.micro.kMc2yuuw.0.0.15.js → uc.micro.kMc2yuuw.0.0.17.js} +0 -0
  244. /package/dist/interface/{utils.BvINh1mj.0.0.15.js → utils.BvINh1mj.0.0.17.js} +0 -0
  245. /package/dist/interface/{uuid.DvF23Exx.0.0.15.js → uuid.DvF23Exx.0.0.17.js} +0 -0
  246. /package/dist/interface/{vue.l0sNRNKZ.0.0.15.js → vue.l0sNRNKZ.0.0.17.js} +0 -0
  247. /package/dist/interface/{zod.BaF2dDCd.0.0.15.js → zod.BaF2dDCd.0.0.17.js} +0 -0
@@ -1,8 +1,6 @@
1
1
  import inspect
2
- import json
3
2
  from contextlib import suppress
4
3
  from copy import deepcopy
5
- from pathlib import Path
6
4
  from typing import Any, Optional, TypeVar, Union, cast
7
5
 
8
6
  from camera_ui_types import (
@@ -24,42 +22,16 @@ from schema import (
24
22
  )
25
23
  from typing_extensions import Literal, overload
26
24
  from utilities.object_path import ObjectPath
27
- from utilities.utils import merge_with
25
+ from utilities.utils import merge, merge_with
28
26
 
29
27
  P = TypeVar("P", str, int, float, bool, dict[Any, Any], list[Any], None)
30
28
 
31
29
 
32
- def merge(
33
- obj_value: Any,
34
- src_value: Any,
35
- key: Union[str, int],
36
- object: Union[dict[str, Any], list[Any]],
37
- source: Union[dict[str, Any], list[Any]],
38
- stack: list[Any],
39
- ) -> Any:
40
- if isinstance(obj_value, list):
41
- return src_value
42
-
43
-
44
- class JsonLmdb(Lmdb[Literal["config"], dict[str, Any]]):
45
- def _pre_key(self, key: Literal["config"]) -> bytes:
46
- return key.encode("utf-8")
47
-
48
- def _post_key(self, key: bytes) -> Literal["config"]:
49
- _key: Any = key.decode("utf-8")
50
- return _key
51
-
52
- def _pre_value(self, value: dict[str, Any]) -> bytes:
53
- return json.dumps(value).encode("utf-8")
54
-
55
- def _post_value(self, value: bytes) -> dict[str, Any]:
56
- return json.loads(value.decode("utf-8"))
57
-
58
-
59
30
  class CameraStorage:
60
31
  def __init__(
61
32
  self,
62
33
  api: PluginAPI,
34
+ plugin_db: Lmdb[Literal["config"], dict[str, Any]],
63
35
  instance: Any,
64
36
  camera_id: str,
65
37
  schema: Optional[JsonSchemaForm] = None,
@@ -67,15 +39,12 @@ class CameraStorage:
67
39
  if schema is None:
68
40
  schema = {}
69
41
  self.__api = api
42
+ self.__plugin_db = plugin_db
70
43
  self.__instance = instance
71
44
  self.__camera_id = camera_id
72
45
  self.schema: JsonSchemaForm = schema or {}
73
46
  self.values: dict[str, Any] = {}
74
47
 
75
- db_path = Path(api.storage_path) / "volume"
76
- self.__db: Lmdb[Literal["config"], dict[str, Any]] = JsonLmdb.open(file=str(db_path), flag="c")
77
-
78
- self.__api.device_manager.once("cameraDeselected", self.__deselected)
79
48
  self.__api.once("shutdown", self.__close)
80
49
 
81
50
  def initializeStorage(self) -> None:
@@ -84,17 +53,10 @@ class CameraStorage:
84
53
  This will load the configuration from the database.
85
54
  """
86
55
 
87
- camera_config: dict[str, Any] = {}
88
-
89
- try:
90
- config: Any = self.__db.get("config") or {}
91
- camera_config = config.get(self.__camera_id, {})
92
- except: # noqa: E722
93
- pass
94
-
56
+ config: Any = self.__plugin_db.get("config") or {}
57
+ camera_config = config.get(self.__camera_id, {})
95
58
  schema_config = generate_json_from_root_schema({"schema": self.schema})
96
-
97
- self.values = merge_with(schema_config, camera_config, merge, [])
59
+ self.values = merge_with(schema_config, camera_config, merge)
98
60
 
99
61
  self.__save_db()
100
62
 
@@ -228,7 +190,7 @@ class CameraStorage:
228
190
  elif isinstance(schema_or_path, dict) and schema is None:
229
191
  new_schema = schema_or_path
230
192
 
231
- self.schema = merge_with(self.schema, new_schema, merge, [])
193
+ self.schema = merge_with(self.schema, new_schema, merge)
232
194
 
233
195
  await self.__resolve_on_get_functions(new_schema)
234
196
 
@@ -258,7 +220,7 @@ class CameraStorage:
258
220
  ObjectPath.delete(self.values, path)
259
221
 
260
222
  if self.__contains_storable_schema(schema):
261
- self.__remove_db()
223
+ self.__save_db()
262
224
 
263
225
  async def changeSchema(self, path: str, new_schema: dict[str, Any]) -> None:
264
226
  """
@@ -274,7 +236,7 @@ class CameraStorage:
274
236
  schema: Optional[JsonSchema] = ObjectPath.get(self.schema, schema_path) or None
275
237
 
276
238
  if schema:
277
- merge_with(schema, new_schema, merge, [])
239
+ merge_with(schema, new_schema, merge)
278
240
  ObjectPath.set(self.schema, schema_path, schema)
279
241
 
280
242
  await self.__resolve_on_get_functions(schema, schema_path)
@@ -362,7 +324,7 @@ class CameraStorage:
362
324
  schema_path = config_path_to_schema_path(new_path)
363
325
  schema_item: Optional[JsonBaseSchema] = get_value_by_path(self.schema, schema_path)
364
326
 
365
- if schema_item:
327
+ if schema_item and schema_item["type"] != "button":
366
328
  on_set_function = schema_item.get("onSet", None)
367
329
  if on_set_function:
368
330
  if inspect.iscoroutinefunction(on_set_function):
@@ -417,25 +379,13 @@ class CameraStorage:
417
379
  return False
418
380
 
419
381
  def __save_db(self) -> None:
420
- config: Any = self.__db.get("config") or {}
382
+ config: Any = self.__plugin_db.get("config") or {}
421
383
  storable_config = self.__filter_storable_values(self.schema)
422
384
 
423
385
  config[self.__camera_id] = storable_config
424
386
 
425
- self.__db.update({"config": config})
426
-
427
- def __remove_db(self) -> None:
428
- config: Any = self.__db.get("config") or {}
429
-
430
- if self.__camera_id in config:
431
- del config[self.__camera_id]
432
- self.__db.update(config)
433
-
434
- def __deselected(self, id: str) -> None:
435
- if id == self.__camera_id:
436
- self.__remove_db()
387
+ self.__plugin_db.update({"config": config})
437
388
 
438
389
  def __close(self) -> None:
439
390
  with suppress(Exception):
440
391
  self.__save_db()
441
- self.__db.close()
@@ -7,11 +7,13 @@ import sys
7
7
  import traceback
8
8
  from asyncio import AbstractEventLoop
9
9
  from contextlib import suppress
10
+ from pathlib import Path
10
11
  from types import ModuleType
11
- from typing import Any, Optional, cast
12
+ from typing import Any, Literal, Optional, cast
12
13
 
13
14
  from camera_ui_types import BasePlugin, CameraDevice
14
15
  from decoder.typings import AuthConfig
16
+ from lmdbm import Lmdb
15
17
  from message_queue import MessageQueue
16
18
  from nats.aio.msg import Msg
17
19
  from plugin_api import PluginAPI
@@ -27,6 +29,7 @@ from typings import (
27
29
  ProxyMessageStructure,
28
30
  )
29
31
  from utilities.connection import ProxyConnection
32
+ from utilities.json_lmdb import JsonLmdb
30
33
  from utilities.packer import unpack
31
34
  from utilities.subscriptions import ProxySubscription
32
35
  from utilities.task import TaskSet
@@ -88,6 +91,7 @@ class PluginChild:
88
91
 
89
92
  self.display_name = sys.argv[1] if len(sys.argv) > 1 else "PluginChild"
90
93
  self.logger = PluginLogger(self.display_name, os.environ["LOGGER_DISABLE_TIMESTAMPS"] == "true")
94
+ self.plugin_db: Optional[Lmdb[Literal["config"], dict[str, Any]]] = None
91
95
 
92
96
  self.subject = f"{os.environ['WORKER_ID']}.ipc.subscriber"
93
97
  self.plugin_subject = f"{os.environ['PLUGIN_ID']}.child"
@@ -104,6 +108,7 @@ class PluginChild:
104
108
  self.plugin: Optional[BasePlugin] = None
105
109
 
106
110
  self.stopped = False
111
+ self.closed = False
107
112
 
108
113
  async def run(self):
109
114
  self.shutdown_event = asyncio.Event()
@@ -136,10 +141,28 @@ class PluginChild:
136
141
  plugin_info = data["plugin"]
137
142
  cameras = data["cameras"]
138
143
 
144
+ db_path = Path(storage_path) / "volume"
145
+ Path(db_path).mkdir(parents=True, exist_ok=True)
146
+
147
+ self.plugin_db = JsonLmdb.open(file=str(db_path), flag="c")
148
+
149
+ config: Any = self.plugin_db.get("config")
150
+ if config is None:
151
+ self.plugin_db.update({"config": {}})
152
+
139
153
  self.api = PluginAPI(
140
- plugin_info, storage_path, config_file, self.logger, self.proxy_endpoints, self.auth
154
+ plugin_info,
155
+ storage_path,
156
+ config_file,
157
+ self.logger,
158
+ self.proxy_endpoints,
159
+ self.auth,
160
+ self.plugin_db,
141
161
  )
142
162
 
163
+ plugin_constructor = self.load_plugin()
164
+ self.plugin = cast(BasePlugin, plugin_constructor(self.logger, self.api))
165
+
143
166
  await asyncio.gather(
144
167
  self.api.core_manager.init(),
145
168
  self.api.device_manager.init(),
@@ -159,9 +182,6 @@ class PluginChild:
159
182
 
160
183
  await asyncio.gather(*(camera_device.init() for camera_device in cameras_devices))
161
184
 
162
- plugin_constructor = self.load_plugin()
163
- self.plugin = cast(BasePlugin, plugin_constructor(self.logger, self.api))
164
-
165
185
  self.api.device_manager.configure_cameras(cameras_devices)
166
186
  self.plugin.configure_cameras(cast(list[CameraDevice], cameras_devices))
167
187
 
@@ -175,6 +195,9 @@ class PluginChild:
175
195
 
176
196
  self.stopped = True
177
197
 
198
+ if self.api:
199
+ self.api.emit("shutdown")
200
+
178
201
  if self.message_queue:
179
202
  self.message_queue.abort_queue()
180
203
 
@@ -182,8 +205,10 @@ class PluginChild:
182
205
  with suppress(Exception):
183
206
  await self.publisher.close()
184
207
 
185
- if self.api:
186
- self.api.emit("shutdown")
208
+ if self.plugin_db:
209
+ await asyncio.sleep(0.5)
210
+ with suppress(Exception):
211
+ self.plugin_db.close()
187
212
 
188
213
  self.shutdown_event.set()
189
214
 
@@ -268,9 +293,27 @@ class PluginChild:
268
293
 
269
294
  if "type" in message:
270
295
  if message["type"] == PLUGIN_COMMAND.START.value and "data" in message:
271
- self.tasks.add(self.start(message["data"]))
296
+ await self.start(message["data"])
272
297
  elif message["type"] == PLUGIN_COMMAND.STOP.value:
273
- self.tasks.add(self.stop())
298
+ await self.stop()
299
+
300
+ async def gracefully_close(self, signame: str, reason: Any = "unknown"):
301
+ if self.stopped or self.closed:
302
+ return
303
+
304
+ self.closed = True
305
+
306
+ self.logger.log(
307
+ f"{self.display_name} is gracefully closing from signal='{signame}' reason='{reason}'..."
308
+ )
309
+
310
+ try:
311
+ stop_task = asyncio.create_task(self.stop(), name=f"{self.display_name} Stop")
312
+ await asyncio.wait_for(stop_task, timeout=2)
313
+ os.kill(os.getpid(), signal.SIGKILL)
314
+ except asyncio.TimeoutError:
315
+ self.logger.warn("Failed to gracefully close before timeout, force quit!")
316
+ os.kill(os.getpid(), signal.SIGKILL)
274
317
 
275
318
  def setup_signal_handlers(self):
276
319
  loop = asyncio.get_running_loop()
@@ -279,20 +322,12 @@ class PluginChild:
279
322
  for signame in ("SIGINT", "SIGTERM"):
280
323
  loop.add_signal_handler(
281
324
  getattr(signal, signame),
282
- lambda signame=signame: self.gracefully_close(signame, getattr(signal, signame)),
325
+ lambda signame=signame: asyncio.create_task(
326
+ self.gracefully_close(signame, getattr(signal, signame)),
327
+ name=f"{self.display_name} Signal",
328
+ ),
283
329
  )
284
330
 
285
- def gracefully_close(self, signame: str, reason: Any = "unknown"):
286
- if self.stopped:
287
- return
288
-
289
- self.logger.log(
290
- f"{self.display_name} is gracefully closing from signal='{signame}' reason='{reason}'..."
291
- )
292
-
293
- self.tasks.add(self.stop())
294
- self.shutdown_event.set()
295
-
296
331
  def handle_exception(self, loop: AbstractEventLoop, context: Any):
297
332
  print("Exception context:", context)
298
333
  traceback.print_exc()
@@ -308,9 +343,10 @@ class PluginChild:
308
343
  self.logger.error(f"Caught exception: {msg}")
309
344
 
310
345
  if loop.is_running():
311
- self.gracefully_close("uncaughtException", msg)
346
+ asyncio.create_task(self.gracefully_close("uncaughtException", msg))
312
347
 
313
348
 
314
349
  if __name__ == "__main__":
315
350
  plugin_child = PluginChild()
316
- asyncio.run(plugin_child.run(), debug=True)
351
+ asyncio.run(plugin_child.run())
352
+ # asyncio.run(plugin_child.run(), debug=True)
@@ -163,7 +163,14 @@ class PluginConfigService:
163
163
  self.set(path_segments[0], self.__config[path_segments[0]], write)
164
164
 
165
165
  def __init(self) -> None:
166
- os.makedirs(os.path.dirname(self.__config_file), exist_ok=True)
166
+ directory = os.path.dirname(self.__config_file)
167
+
168
+ if not os.path.exists(directory):
169
+ os.makedirs(directory)
170
+
171
+ if not os.path.exists(self.__config_file):
172
+ open(self.__config_file, "a").close()
173
+
167
174
  self.__read()
168
175
 
169
176
  def __read(self) -> None:
@@ -1,5 +1,8 @@
1
+ from typing import Any, Literal
2
+
1
3
  from config_service import PluginConfigService
2
4
  from decoder.typings import AuthConfig
5
+ from lmdbm import Lmdb
3
6
  from plugin_logger import PluginLogger
4
7
  from pyeecui.asyncio import AsyncIOEventEmitter
5
8
  from typings import PluginInfo
@@ -14,6 +17,7 @@ class PluginAPI(AsyncIOEventEmitter):
14
17
  logger: PluginLogger,
15
18
  proxy_endpoints: list[str],
16
19
  auth: AuthConfig,
20
+ plugin_db: Lmdb[Literal["config"], dict[str, Any]],
17
21
  ) -> None:
18
22
  super().__init__()
19
23
 
@@ -25,6 +29,6 @@ class PluginAPI(AsyncIOEventEmitter):
25
29
  self.config_file = config_file
26
30
 
27
31
  self.config_service = PluginConfigService(config_file)
28
- self.storage_controller = StorageController(self)
32
+ self.storage_controller = StorageController(self, plugin_db)
29
33
  self.core_manager = CoreManager(self, logger, plugin, proxy_endpoints, auth)
30
34
  self.device_manager = DeviceManager(self, logger, plugin, proxy_endpoints, auth)
@@ -10,6 +10,7 @@ from uuid import uuid4
10
10
 
11
11
  import aiohttp
12
12
  from cachetools import LRUCache, cached
13
+ from camera.iou import merge_detections
13
14
  from camera.polygon import are_motion_detections_valid, are_object_detections_valid
14
15
  from camera.video_frame import MotionFrame, VideoFrame
15
16
  from camera_ui_types import (
@@ -68,6 +69,7 @@ from typings import (
68
69
  ClientType,
69
70
  Delegates,
70
71
  DeserializedError,
72
+ FrameSubscribtion,
71
73
  PluginInfo,
72
74
  ProxyMessageStructure,
73
75
  )
@@ -190,13 +192,13 @@ class CameraDeviceProxy:
190
192
  self.camera_subscriber: Optional[ProxySubscription] = None
191
193
  self.camera_plugin_subscriber: Optional[ProxySubscription] = None
192
194
  self.signaling_subscriber: Optional[ProxySubscription] = None
193
- self.frame_subscriber: Optional[ProxySubscription] = None
194
- self.motion_frame_subscriber: Optional[ProxySubscription] = None
195
+ self.frame_subscribers: list[FrameSubscribtion] = []
196
+ self.motion_frame_subscribers: list[FrameSubscribtion] = []
195
197
 
196
198
  self.tasks: TaskSet = TaskSet(f"{self.plugin['name']} - {self.name} - CameraDeviceProxy")
197
199
  self.message_queue: Optional[MessageQueue] = None
198
200
  self.active_requests: set[str] = set()
199
- self.active_motion_requests = 0
201
+ self.active_motion_requests: set[str] = set()
200
202
 
201
203
  # print(("INIT camera device with clientSubject", self.subject))
202
204
 
@@ -425,24 +427,24 @@ class CameraDeviceProxy:
425
427
 
426
428
  if prebuffer_duration > 0:
427
429
  request_type = "prebuffer"
428
- prebuffer_duration = 5 if prebuffer_duration > 5 else prebuffer_duration
430
+ prebuffer_duration = min(prebuffer_duration, 5)
429
431
 
430
432
  request_id = f"{str(uuid4())}-{request_type}"
431
433
 
432
434
  try:
433
435
  metadata = await self.__connect_to_decoder(request_id)
436
+ frame_subscriber = await self.frame_publisher.subscribe(self.frame_subject)
434
437
 
435
- if not self.frame_subscriber:
436
- self.frame_subscriber = await self.frame_publisher.subscribe(self.frame_subject)
438
+ self.frame_subscribers.append({"request_id": request_id, "subscriber": frame_subscriber})
437
439
 
438
- async for msg in self.frame_subscriber.subscriber.messages:
439
- try:
440
+ try:
441
+ async for msg in frame_subscriber.subscriber.messages:
440
442
  if (
441
443
  not self.initialized
442
444
  or len(self.active_requests) == 0
443
445
  or request_id not in self.active_requests
444
446
  ):
445
- break
447
+ return
446
448
 
447
449
  if len(msg.data) == 0:
448
450
  continue
@@ -450,35 +452,39 @@ class CameraDeviceProxy:
450
452
  frame_data: FrameData = unpack(msg.data)
451
453
 
452
454
  yield VideoFrame(self.id, self.frame_publisher, frame_data, metadata, prebuffer_duration)
453
- except Exception as e:
454
- if self.initialized:
455
- self.logger.error("Error while processing frame:", e)
456
- else:
457
- break
455
+
456
+ except GeneratorExit:
457
+ return
458
458
 
459
459
  except asyncio.CancelledError:
460
- pass
460
+ return
461
461
  except Exception as e:
462
462
  if self.initialized:
463
463
  self.logger.error("Error while generating frames:", e)
464
+ raise
464
465
  finally:
465
- self.tasks.add(self.__disconnect_from_decoder(request_id))
466
+ await self.__disconnect_from_decoder(request_id)
466
467
 
467
468
  async def get_motion_frames(self) -> AsyncGenerator[MotionFrame, None]:
468
469
  if not self.motion_frame_publisher:
469
470
  raise Exception("Motion Frame Publisher is not initialized")
470
471
 
471
- self.active_motion_requests += 1
472
+ request_id = f"{str(uuid4())}-motion"
472
473
 
473
474
  try:
474
- if not self.motion_frame_subscriber:
475
- self.motion_frame_subscriber = await self.motion_frame_publisher.subscribe(
476
- self.motion_frame_subject
477
- )
475
+ motion_frame_subscriber = await self.motion_frame_publisher.subscribe(self.motion_frame_subject)
478
476
 
479
- async for msg in self.motion_frame_subscriber.subscriber.messages:
480
- try:
481
- if not self.initialized or self.active_motion_requests <= 0:
477
+ self.motion_frame_subscribers.append(
478
+ {"request_id": request_id, "subscriber": motion_frame_subscriber}
479
+ )
480
+
481
+ try:
482
+ async for msg in motion_frame_subscriber.subscriber.messages:
483
+ if (
484
+ not self.initialized
485
+ or len(self.active_motion_requests) == 0
486
+ or request_id not in self.active_motion_requests
487
+ ):
482
488
  break
483
489
 
484
490
  if not msg or not msg.data or len(msg.data) == 0:
@@ -499,22 +505,30 @@ class CameraDeviceProxy:
499
505
  motion_state,
500
506
  motion_frame["metadata"],
501
507
  )
502
- except Exception as e:
503
- if self.initialized:
504
- self.logger.error("Error while processing motion frame:", e)
505
- else:
506
- break
508
+
509
+ except GeneratorExit:
510
+ return
507
511
 
508
512
  except asyncio.CancelledError:
509
513
  pass
510
514
  except Exception as e:
511
515
  if self.initialized:
512
516
  self.logger.error("Error while generating motion frames:", e)
517
+ raise
513
518
  finally:
514
- self.active_motion_requests -= 1
519
+ if request_id in self.active_motion_requests:
520
+ self.active_motion_requests.remove(request_id)
521
+
522
+ motion_frame_subscribtion = next(
523
+ (sub for sub in self.motion_frame_subscribers if sub["request_id"] == request_id), None
524
+ )
525
+
526
+ if motion_frame_subscribtion:
527
+ self.motion_frame_subscribers.remove(motion_frame_subscribtion)
528
+ await motion_frame_subscribtion["subscriber"].close()
515
529
 
516
- if self.active_motion_requests <= 0:
517
- self.tasks.add(self.__close_motion_frame_subscriber())
530
+ if len(self.motion_frame_subscribers) == 0:
531
+ await self.__close_motion_frame_subscribers()
518
532
 
519
533
  @overload
520
534
  def get_value(self, state_name: Literal["light"]) -> LightState: ...
@@ -913,6 +927,8 @@ class CameraDeviceProxy:
913
927
  det["boundingBox"] = cast(tuple[int, int, int, int], tuple(det["boundingBox"]))
914
928
  det["confidence"] = float(det["confidence"])
915
929
 
930
+ motion_event["detections"] = merge_detections(motion_event["detections"])
931
+
916
932
  motion_event["detections"] = are_motion_detections_valid(
917
933
  motion_event["detections"], self.activity_zones, self.activity_settings
918
934
  )
@@ -1433,37 +1449,48 @@ class CameraDeviceProxy:
1433
1449
  metadata = metadata_response.get("metadata")
1434
1450
 
1435
1451
  return metadata
1436
- except: # noqa: E722
1437
- self.logger.error("Failed to get metadata! Frame Worker FFmpeg process might not be running")
1452
+ except Exception as e:
1453
+ self.logger.error("Failed to get metadata! Frame Worker FFmpeg process might not be running", e)
1438
1454
 
1439
1455
  async def __disconnect_from_decoder(self, request_id: str) -> None:
1440
1456
  if request_id in self.active_requests:
1441
1457
  self.active_requests.remove(request_id)
1442
1458
 
1443
- if not self.signaling_publisher:
1444
- raise Exception("Signaling Publisher not initialized")
1459
+ frame_subscription = next(
1460
+ (sub for sub in self.frame_subscribers if sub["request_id"] == request_id), None
1461
+ )
1445
1462
 
1446
- message: SignalingRequest = {
1447
- "type": "disconnect",
1448
- "requestId": request_id,
1449
- "cameraId": self.id,
1450
- "pluginId": self.plugin["id"],
1451
- }
1463
+ if frame_subscription:
1464
+ self.frame_subscribers.remove(frame_subscription)
1465
+ await frame_subscription["subscriber"].close()
1452
1466
 
1453
- await self.signaling_publisher.publish(self.signaling_target_subject, message)
1467
+ if self.signaling_publisher:
1468
+ message: SignalingRequest = {
1469
+ "type": "disconnect",
1470
+ "requestId": request_id,
1471
+ "cameraId": self.id,
1472
+ "pluginId": self.plugin["id"],
1473
+ }
1454
1474
 
1455
- async def __close_frame_subscriber(self) -> None:
1456
- with suppress(Exception):
1457
- if self.frame_subscriber:
1458
- await self.frame_subscriber.close()
1459
- self.frame_subscriber = None
1475
+ await self.signaling_publisher.publish(self.signaling_target_subject, message)
1476
+
1477
+ async def __close_frame_subscribers(self) -> None:
1478
+ self.active_requests.clear()
1479
+
1480
+ for sub in self.frame_subscribers:
1481
+ with suppress(Exception):
1482
+ await sub["subscriber"].close()
1460
1483
 
1461
- async def __close_motion_frame_subscriber(self) -> None:
1462
- if self.motion_frame_subscriber:
1484
+ self.frame_subscribers.clear()
1485
+
1486
+ async def __close_motion_frame_subscribers(self) -> None:
1487
+ self.active_motion_requests.clear()
1488
+
1489
+ for sub in self.motion_frame_subscribers:
1463
1490
  with suppress(Exception):
1464
- await self.motion_frame_subscriber.close()
1491
+ await sub["subscriber"].close()
1465
1492
 
1466
- self.motion_frame_subscriber = None
1493
+ self.motion_frame_subscribers.clear()
1467
1494
 
1468
1495
  async def __request_handler(self, message: ProxyMessageStructure) -> None:
1469
1496
  if not self.message_queue:
@@ -1565,8 +1592,16 @@ class CameraDeviceProxy:
1565
1592
  if message["requestId"] in self.active_requests:
1566
1593
  self.active_requests.remove(message["requestId"])
1567
1594
 
1595
+ frame_subscribtion = next(
1596
+ (sub for sub in self.frame_subscribers if sub["request_id"] == message["requestId"]), None
1597
+ )
1598
+
1599
+ if frame_subscribtion:
1600
+ self.frame_subscribers.remove(frame_subscribtion)
1601
+ await frame_subscribtion["subscriber"].close()
1602
+
1568
1603
  if len(self.active_requests) == 0:
1569
- self.tasks.add(self.__close_frame_subscriber())
1604
+ self.tasks.add(self.__close_frame_subscribers())
1570
1605
 
1571
1606
  async def __respond_to_signaling_message(self, msg: Msg, message: PingMessage) -> None:
1572
1607
  try:
@@ -41,10 +41,10 @@ class CoreManager(AsyncIOEventEmitter):
41
41
  self.cm_subject = "coreManager.subscriber"
42
42
 
43
43
  self.publisher: Optional[ProxyConnection] = None
44
- self.dm_publisher: Optional[ProxyConnection] = None
44
+ self.cm_publisher: Optional[ProxyConnection] = None
45
45
 
46
46
  self.subscriber: Optional[ProxySubscription] = None
47
- self.dm_subscriber: Optional[ProxySubscription] = None
47
+ self.cm_subscriber: Optional[ProxySubscription] = None
48
48
 
49
49
  self.tasks: TaskSet = TaskSet(f"{self.plugin['name']} CoreManager")
50
50
  self.message_queue: Optional[MessageQueue] = None
@@ -64,8 +64,8 @@ class CoreManager(AsyncIOEventEmitter):
64
64
  self.publisher = ProxyConnection(self.subject, servers, self.auth)
65
65
  await self.publisher.connect()
66
66
 
67
- self.dm_publisher = ProxyConnection(self.cm_subject, servers, self.auth)
68
- await self.dm_publisher.connect()
67
+ self.cm_publisher = ProxyConnection(self.cm_subject, servers, self.auth)
68
+ await self.cm_publisher.connect()
69
69
 
70
70
  self.subscriber = await self.publisher.subscribe(subject=self.subject)
71
71
  self.message_queue = MessageQueue(
@@ -75,8 +75,8 @@ class CoreManager(AsyncIOEventEmitter):
75
75
  self.__request_handler,
76
76
  )
77
77
 
78
- self.dm_subscriber = await self.dm_publisher.subscribe(subject=self.cm_subject)
79
- self.dm_subscriber.on("message", self.__on_proxy_message)
78
+ self.cm_subscriber = await self.cm_publisher.subscribe(subject=self.cm_subject)
79
+ self.cm_subscriber.on("message", self.__on_proxy_message)
80
80
 
81
81
  async def get_ffmpeg_path(self) -> str:
82
82
  return await self.__on_request("getFFmpegPath")
@@ -141,5 +141,5 @@ class CoreManager(AsyncIOEventEmitter):
141
141
  if self.publisher:
142
142
  await self.publisher.close()
143
143
 
144
- if self.dm_publisher:
145
- await self.dm_publisher.close()
144
+ if self.cm_publisher:
145
+ await self.cm_publisher.close()