frontengine 1.0.48__tar.gz → 1.0.50__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. {frontengine-1.0.48 → frontengine-1.0.50}/PKG-INFO +1 -20
  2. {frontengine-1.0.48 → frontengine-1.0.50}/README.md +0 -19
  3. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/main_ui.py +42 -13
  4. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/control_center/control_center_ui.py +39 -12
  5. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/presentation/presentation_setting_ui.py +7 -6
  6. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/user_setting/user_setting_file.py +0 -6
  7. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/multi_language/english.py +0 -24
  8. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/multi_language/traditional_chinese.py +0 -24
  9. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/remote/remote_server.py +1 -3
  10. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/screen_privacy/capture_affinity.py +6 -3
  11. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/virtual_camera/camera_feed.py +1 -1
  12. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/virtual_camera/virtual_camera.py +4 -4
  13. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine.egg-info/PKG-INFO +1 -20
  14. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine.egg-info/SOURCES.txt +0 -12
  15. {frontengine-1.0.48 → frontengine-1.0.50}/pyproject.toml +1 -1
  16. frontengine-1.0.48/frontengine/show/gaming/crosshair_widget.py +0 -160
  17. frontengine-1.0.48/frontengine/show/teleprompter/teleprompter_widget.py +0 -171
  18. frontengine-1.0.48/frontengine/ui/page/stream/stream_setting_ui.py +0 -351
  19. frontengine-1.0.48/frontengine/utils/obs/obs_client.py +0 -148
  20. frontengine-1.0.48/frontengine/utils/obs/obs_protocol.py +0 -140
  21. frontengine-1.0.48/frontengine/utils/obs/websocket_frames.py +0 -147
  22. frontengine-1.0.48/frontengine/utils/soundboard/soundboard.py +0 -172
  23. frontengine-1.0.48/frontengine/utils/virtual_camera/__init__.py +0 -0
  24. frontengine-1.0.48/frontengine/utils/weather/__init__.py +0 -0
  25. frontengine-1.0.48/frontengine/utils/window_pin/__init__.py +0 -0
  26. frontengine-1.0.48/frontengine/utils/workshop/__init__.py +0 -0
  27. frontengine-1.0.48/frontengine/worker/__init__.py +0 -0
  28. {frontengine-1.0.48 → frontengine-1.0.50}/LICENSE +0 -0
  29. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/__init__.py +0 -0
  30. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/__main__.py +0 -0
  31. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/__init__.py +0 -0
  32. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/base_widget.py +0 -0
  33. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/camera/__init__.py +0 -0
  34. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/camera/camera_widget.py +0 -0
  35. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/canvas/__init__.py +0 -0
  36. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/canvas/whiteboard_widget.py +0 -0
  37. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/capture/__init__.py +0 -0
  38. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/capture/region_capture.py +0 -0
  39. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/focus_shield/__init__.py +0 -0
  40. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/focus_shield/focus_shield_widget.py +0 -0
  41. {frontengine-1.0.48/frontengine/show/gaming → frontengine-1.0.50/frontengine/show/gif}/__init__.py +0 -0
  42. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/gif/paint_gif.py +0 -0
  43. {frontengine-1.0.48/frontengine/show/gif → frontengine-1.0.50/frontengine/show/image}/__init__.py +0 -0
  44. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/image/paint_image.py +0 -0
  45. {frontengine-1.0.48/frontengine/show/image → frontengine-1.0.50/frontengine/show/load}/__init__.py +0 -0
  46. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/load/load_someone_make_ui.py +0 -0
  47. {frontengine-1.0.48/frontengine/show/load → frontengine-1.0.50/frontengine/show/measure}/__init__.py +0 -0
  48. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/measure/measure_widget.py +0 -0
  49. {frontengine-1.0.48/frontengine/show/measure → frontengine-1.0.50/frontengine/show/monitor}/__init__.py +0 -0
  50. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/monitor/monitor_widget.py +0 -0
  51. {frontengine-1.0.48/frontengine/show/monitor → frontengine-1.0.50/frontengine/show/notes}/__init__.py +0 -0
  52. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/notes/sticky_note_widget.py +0 -0
  53. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/overlay_factory.py +0 -0
  54. {frontengine-1.0.48/frontengine/show/notes → frontengine-1.0.50/frontengine/show/particle}/__init__.py +0 -0
  55. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/particle/particle_ui.py +0 -0
  56. {frontengine-1.0.48/frontengine/show/particle → frontengine-1.0.50/frontengine/show/pet}/__init__.py +0 -0
  57. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/pet/desktop_pet.py +0 -0
  58. {frontengine-1.0.48/frontengine/show/pet → frontengine-1.0.50/frontengine/show/presentation}/__init__.py +0 -0
  59. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/presentation/annotation_overlay.py +0 -0
  60. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/presentation/cursor_effects.py +0 -0
  61. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/presentation/keystroke_display.py +0 -0
  62. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/presentation/magnifier.py +0 -0
  63. {frontengine-1.0.48/frontengine/show/presentation → frontengine-1.0.50/frontengine/show/scene}/__init__.py +0 -0
  64. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/scene/extend_graphic_scene.py +0 -0
  65. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/scene/extend_graphic_view.py +0 -0
  66. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/scene/scene.py +0 -0
  67. {frontengine-1.0.48/frontengine/show/scene → frontengine-1.0.50/frontengine/show/screen_care}/__init__.py +0 -0
  68. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/screen_care/color_vision_widget.py +0 -0
  69. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/screen_care/screen_filter.py +0 -0
  70. {frontengine-1.0.48/frontengine/show/screen_care → frontengine-1.0.50/frontengine/show/sound_player}/__init__.py +0 -0
  71. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/sound_player/sound_effect.py +0 -0
  72. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/sound_player/sound_player.py +0 -0
  73. {frontengine-1.0.48/frontengine/show/sound_player → frontengine-1.0.50/frontengine/show/spectrum}/__init__.py +0 -0
  74. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/spectrum/spectrum_widget.py +0 -0
  75. {frontengine-1.0.48/frontengine/show/spectrum → frontengine-1.0.50/frontengine/show/text}/__init__.py +0 -0
  76. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/text/draw_text.py +0 -0
  77. {frontengine-1.0.48/frontengine/show/teleprompter → frontengine-1.0.50/frontengine/show/toast}/__init__.py +0 -0
  78. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/toast/toast_widget.py +0 -0
  79. {frontengine-1.0.48/frontengine/show/text → frontengine-1.0.50/frontengine/show/video}/__init__.py +0 -0
  80. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/video/video_player.py +0 -0
  81. {frontengine-1.0.48/frontengine/show/toast → frontengine-1.0.50/frontengine/show/wallpaper}/__init__.py +0 -0
  82. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/wallpaper/wallpaper_widget.py +0 -0
  83. {frontengine-1.0.48/frontengine/show/video → frontengine-1.0.50/frontengine/show/web}/__init__.py +0 -0
  84. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/web/webview.py +0 -0
  85. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/show/window_helpers.py +0 -0
  86. {frontengine-1.0.48/frontengine/show/wallpaper → frontengine-1.0.50/frontengine/system_tray}/__init__.py +0 -0
  87. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/system_tray/extend_system_tray.py +0 -0
  88. {frontengine-1.0.48/frontengine/show/web → frontengine-1.0.50/frontengine/ui}/__init__.py +0 -0
  89. {frontengine-1.0.48/frontengine/system_tray → frontengine-1.0.50/frontengine/ui/color}/__init__.py +0 -0
  90. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/color/global_color.py +0 -0
  91. {frontengine-1.0.48/frontengine/ui → frontengine-1.0.50/frontengine/ui/dialog}/__init__.py +0 -0
  92. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/dialog/app_profile_dialog.py +0 -0
  93. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
  94. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/dialog/clipboard_dialog.py +0 -0
  95. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
  96. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/dialog/reminder_dialog.py +0 -0
  97. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/dialog/remote_control_dialog.py +0 -0
  98. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/dialog/save_file_dialog.py +0 -0
  99. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/dialog/screen_privacy_dialog.py +0 -0
  100. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/dialog/screen_text_dialog.py +0 -0
  101. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/dialog/signage_dialog.py +0 -0
  102. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/dialog/smart_pause_dialog.py +0 -0
  103. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/dialog/usage_report_dialog.py +0 -0
  104. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/dialog/window_pin_dialog.py +0 -0
  105. {frontengine-1.0.48/frontengine/ui/color → frontengine-1.0.50/frontengine/ui/menu}/__init__.py +0 -0
  106. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/menu/help_menu.py +0 -0
  107. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/menu/how_to_menu.py +0 -0
  108. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/menu/language_menu.py +0 -0
  109. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/menu/preset_menu.py +0 -0
  110. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/menu/settings_menu.py +0 -0
  111. {frontengine-1.0.48/frontengine/ui/dialog → frontengine-1.0.50/frontengine/ui/page}/__init__.py +0 -0
  112. {frontengine-1.0.48/frontengine/ui/menu → frontengine-1.0.50/frontengine/ui/page/control_center}/__init__.py +0 -0
  113. {frontengine-1.0.48/frontengine/ui/page → frontengine-1.0.50/frontengine/ui/page/focus}/__init__.py +0 -0
  114. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/focus/focus_setting_ui.py +0 -0
  115. {frontengine-1.0.48/frontengine/ui/page/control_center → frontengine-1.0.50/frontengine/ui/page/gif}/__init__.py +0 -0
  116. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
  117. {frontengine-1.0.48/frontengine/ui/page/focus → frontengine-1.0.50/frontengine/ui/page/image}/__init__.py +0 -0
  118. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/image/image_setting_ui.py +0 -0
  119. {frontengine-1.0.48/frontengine/ui/page/gif → frontengine-1.0.50/frontengine/ui/page/particle}/__init__.py +0 -0
  120. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
  121. {frontengine-1.0.48/frontengine/ui/page/image → frontengine-1.0.50/frontengine/ui/page/pet}/__init__.py +0 -0
  122. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/pet/pet_setting_ui.py +0 -0
  123. {frontengine-1.0.48/frontengine/ui/page/particle → frontengine-1.0.50/frontengine/ui/page/presentation}/__init__.py +0 -0
  124. {frontengine-1.0.48/frontengine/ui/page/pet → frontengine-1.0.50/frontengine/ui/page/scene_setting}/__init__.py +0 -0
  125. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
  126. {frontengine-1.0.48/frontengine/ui/page/presentation → frontengine-1.0.50/frontengine/ui/page/scene_setting/scene_page}/__init__.py +0 -0
  127. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
  128. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
  129. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
  130. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
  131. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
  132. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
  133. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
  134. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
  135. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
  136. {frontengine-1.0.48/frontengine/ui/page/scene_setting → frontengine-1.0.50/frontengine/ui/page/screen_care}/__init__.py +0 -0
  137. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/screen_care/screen_care_setting_ui.py +1 -1
  138. {frontengine-1.0.48/frontengine/ui/page/scene_setting/scene_page → frontengine-1.0.50/frontengine/ui/page/sound_player}/__init__.py +0 -0
  139. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
  140. {frontengine-1.0.48/frontengine/ui/page/screen_care → frontengine-1.0.50/frontengine/ui/page/text}/__init__.py +0 -0
  141. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/text/text_setting_ui.py +0 -0
  142. {frontengine-1.0.48/frontengine/ui/page/sound_player → frontengine-1.0.50/frontengine/ui/page/tools}/__init__.py +0 -0
  143. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/tools/tools_setting_ui.py +0 -0
  144. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/utils.py +0 -0
  145. {frontengine-1.0.48/frontengine/ui/page/stream → frontengine-1.0.50/frontengine/ui/page/video}/__init__.py +0 -0
  146. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/video/video_setting_ui.py +0 -0
  147. {frontengine-1.0.48/frontengine/ui/page/text → frontengine-1.0.50/frontengine/ui/page/wallpaper}/__init__.py +0 -0
  148. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/wallpaper/wallpaper_setting_ui.py +0 -0
  149. {frontengine-1.0.48/frontengine/ui/page/tools → frontengine-1.0.50/frontengine/ui/page/web}/__init__.py +0 -0
  150. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/web/web_setting_ui.py +0 -0
  151. {frontengine-1.0.48/frontengine/ui/page/video → frontengine-1.0.50/frontengine/ui/page/widgets}/__init__.py +0 -0
  152. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/ui/page/widgets/widgets_setting_ui.py +0 -0
  153. {frontengine-1.0.48/frontengine/ui/page/wallpaper → frontengine-1.0.50/frontengine/user_setting}/__init__.py +0 -0
  154. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/user_setting/preset_repository.py +0 -0
  155. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/user_setting/scene_setting.py +0 -0
  156. {frontengine-1.0.48/frontengine/ui/page/web → frontengine-1.0.50/frontengine/utils}/__init__.py +0 -0
  157. {frontengine-1.0.48/frontengine/ui/page/widgets → frontengine-1.0.50/frontengine/utils/app_profile}/__init__.py +0 -0
  158. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/app_profile/app_profile_service.py +0 -0
  159. {frontengine-1.0.48/frontengine/user_setting → frontengine-1.0.50/frontengine/utils/audio_meter}/__init__.py +0 -0
  160. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/audio_meter/audio_envelope.py +0 -0
  161. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/audio_meter/loopback_capture.py +0 -0
  162. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/audio_meter/microphone_meter.py +0 -0
  163. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/audio_meter/screen_audio.py +0 -0
  164. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/audio_meter/spectrum_analyzer.py +0 -0
  165. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/audio_meter/system_audio_meter.py +0 -0
  166. {frontengine-1.0.48/frontengine/utils → frontengine-1.0.50/frontengine/utils/autostart}/__init__.py +0 -0
  167. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/autostart/autostart_service.py +0 -0
  168. {frontengine-1.0.48/frontengine/utils/app_profile → frontengine-1.0.50/frontengine/utils/break_reminder}/__init__.py +0 -0
  169. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/break_reminder/break_reminder.py +0 -0
  170. {frontengine-1.0.48/frontengine/utils/audio_meter → frontengine-1.0.50/frontengine/utils/browser}/__init__.py +0 -0
  171. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/browser/browser.py +0 -0
  172. {frontengine-1.0.48/frontengine/utils/autostart → frontengine-1.0.50/frontengine/utils/clipboard}/__init__.py +0 -0
  173. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/clipboard/clipboard_history.py +0 -0
  174. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/clipboard/clipboard_watcher.py +0 -0
  175. {frontengine-1.0.48/frontengine/utils/break_reminder → frontengine-1.0.50/frontengine/utils/color_vision}/__init__.py +0 -0
  176. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/color_vision/color_vision.py +0 -0
  177. {frontengine-1.0.48/frontengine/utils/browser → frontengine-1.0.50/frontengine/utils/critical_exit}/__init__.py +0 -0
  178. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
  179. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/critical_exit/critical_exit.py +0 -0
  180. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/critical_exit/win32_vk.py +0 -0
  181. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/exception/__init__.py +0 -0
  182. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/exception/exception_tags.py +0 -0
  183. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/exception/exceptions.py +0 -0
  184. {frontengine-1.0.48/frontengine/utils/clipboard → frontengine-1.0.50/frontengine/utils/file}/__init__.py +0 -0
  185. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/file/open/__init__.py +0 -0
  186. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/file/open/open_file.py +0 -0
  187. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/file/save/__init__.py +0 -0
  188. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/file/save/save_file.py +0 -0
  189. {frontengine-1.0.48/frontengine/utils/color_vision → frontengine-1.0.50/frontengine/utils/focus_shield}/__init__.py +0 -0
  190. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/focus_shield/focus_shield.py +0 -0
  191. {frontengine-1.0.48/frontengine/utils/critical_exit → frontengine-1.0.50/frontengine/utils/focus_timer}/__init__.py +0 -0
  192. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/focus_timer/focus_timer.py +0 -0
  193. {frontengine-1.0.48/frontengine/utils/file → frontengine-1.0.50/frontengine/utils/hotkey}/__init__.py +0 -0
  194. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/hotkey/hotkey_service.py +0 -0
  195. {frontengine-1.0.48/frontengine/utils/focus_shield → frontengine-1.0.50/frontengine/utils/input_watch}/__init__.py +0 -0
  196. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/input_watch/input_watch_service.py +0 -0
  197. {frontengine-1.0.48/frontengine/utils/focus_timer → frontengine-1.0.50/frontengine/utils/json}/__init__.py +0 -0
  198. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/json/json_file.py +0 -0
  199. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/json/json_repository.py +0 -0
  200. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/json_format/__init__.py +0 -0
  201. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/json_format/json_process.py +0 -0
  202. {frontengine-1.0.48/frontengine/utils/hotkey → frontengine-1.0.50/frontengine/utils/logging}/__init__.py +0 -0
  203. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/logging/loggin_instance.py +0 -0
  204. {frontengine-1.0.48/frontengine/utils/input_watch → frontengine-1.0.50/frontengine/utils/measure}/__init__.py +0 -0
  205. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/measure/measure.py +0 -0
  206. {frontengine-1.0.48/frontengine/utils/json → frontengine-1.0.50/frontengine/utils/midi}/__init__.py +0 -0
  207. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/midi/midi_input.py +0 -0
  208. {frontengine-1.0.48/frontengine/utils/logging → frontengine-1.0.50/frontengine/utils/multi_language}/__init__.py +0 -0
  209. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/multi_language/france.py +0 -0
  210. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/multi_language/germany.py +0 -0
  211. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/multi_language/italy.py +0 -0
  212. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/multi_language/language_wrapper.py +0 -0
  213. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/multi_language/russian.py +0 -0
  214. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/multi_language/simplified_chinese.py +0 -0
  215. {frontengine-1.0.48/frontengine/utils/measure → frontengine-1.0.50/frontengine/utils/now_playing}/__init__.py +0 -0
  216. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/now_playing/now_playing.py +0 -0
  217. {frontengine-1.0.48/frontengine/utils/midi → frontengine-1.0.50/frontengine/utils/pet_chat}/__init__.py +0 -0
  218. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/pet_chat/pet_chat_service.py +0 -0
  219. {frontengine-1.0.48/frontengine/utils/multi_language → frontengine-1.0.50/frontengine/utils/platform_info}/__init__.py +0 -0
  220. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/platform_info/platform_info.py +0 -0
  221. {frontengine-1.0.48/frontengine/utils/now_playing → frontengine-1.0.50/frontengine/utils/playlist}/__init__.py +0 -0
  222. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/playlist/playlist.py +0 -0
  223. {frontengine-1.0.48/frontengine/utils/obs → frontengine-1.0.50/frontengine/utils/plugins}/__init__.py +0 -0
  224. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/plugins/plugin_loader.py +0 -0
  225. {frontengine-1.0.48/frontengine/utils/pet_chat → frontengine-1.0.50/frontengine/utils/power_mode}/__init__.py +0 -0
  226. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/power_mode/power_mode.py +0 -0
  227. {frontengine-1.0.48/frontengine/utils/platform_info → frontengine-1.0.50/frontengine/utils/preset_schedule}/__init__.py +0 -0
  228. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
  229. {frontengine-1.0.48/frontengine/utils/playlist → frontengine-1.0.50/frontengine/utils/recording}/__init__.py +0 -0
  230. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/recording/frame_recorder.py +0 -0
  231. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/recording/gif_writer.py +0 -0
  232. {frontengine-1.0.48/frontengine/utils/plugins → frontengine-1.0.50/frontengine/utils/redirect_manager}/__init__.py +0 -0
  233. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
  234. {frontengine-1.0.48/frontengine/utils/power_mode → frontengine-1.0.50/frontengine/utils/reminder}/__init__.py +0 -0
  235. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/reminder/reminder_service.py +0 -0
  236. {frontengine-1.0.48/frontengine/utils/preset_schedule → frontengine-1.0.50/frontengine/utils/remote}/__init__.py +0 -0
  237. {frontengine-1.0.48/frontengine/utils/recording → frontengine-1.0.50/frontengine/utils/screen_privacy}/__init__.py +0 -0
  238. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/screen_privacy/share_watch.py +0 -0
  239. {frontengine-1.0.48/frontengine/utils/redirect_manager → frontengine-1.0.50/frontengine/utils/screen_text}/__init__.py +0 -0
  240. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/screen_text/screen_text_service.py +0 -0
  241. {frontengine-1.0.48/frontengine/utils/reminder → frontengine-1.0.50/frontengine/utils/signage}/__init__.py +0 -0
  242. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/signage/signage_service.py +0 -0
  243. {frontengine-1.0.48/frontengine/utils/remote → frontengine-1.0.50/frontengine/utils/smart_pause}/__init__.py +0 -0
  244. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/smart_pause/pause_rules.py +0 -0
  245. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
  246. {frontengine-1.0.48/frontengine/utils/screen_privacy → frontengine-1.0.50/frontengine/utils/system_stats}/__init__.py +0 -0
  247. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/system_stats/system_stats.py +0 -0
  248. {frontengine-1.0.48/frontengine/utils/screen_text → frontengine-1.0.50/frontengine/utils/text_source}/__init__.py +0 -0
  249. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/text_source/text_source.py +0 -0
  250. {frontengine-1.0.48/frontengine/utils/signage → frontengine-1.0.50/frontengine/utils/theme_schedule}/__init__.py +0 -0
  251. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
  252. {frontengine-1.0.48/frontengine/utils/smart_pause → frontengine-1.0.50/frontengine/utils/usage_tracking}/__init__.py +0 -0
  253. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/usage_tracking/usage_service.py +0 -0
  254. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/usage_tracking/usage_tracker.py +0 -0
  255. {frontengine-1.0.48/frontengine/utils/soundboard → frontengine-1.0.50/frontengine/utils/virtual_camera}/__init__.py +0 -0
  256. {frontengine-1.0.48/frontengine/utils/system_stats → frontengine-1.0.50/frontengine/utils/weather}/__init__.py +0 -0
  257. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/weather/weather_service.py +0 -0
  258. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/web_url.py +0 -0
  259. {frontengine-1.0.48/frontengine/utils/text_source → frontengine-1.0.50/frontengine/utils/window_pin}/__init__.py +0 -0
  260. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/window_pin/window_layout.py +0 -0
  261. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/window_pin/window_pin.py +0 -0
  262. {frontengine-1.0.48/frontengine/utils/theme_schedule → frontengine-1.0.50/frontengine/utils/workshop}/__init__.py +0 -0
  263. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/utils/workshop/workshop_content.py +0 -0
  264. {frontengine-1.0.48/frontengine/utils/usage_tracking → frontengine-1.0.50/frontengine/worker}/__init__.py +0 -0
  265. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine/worker/qthread_worker.py +0 -0
  266. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine.egg-info/dependency_links.txt +0 -0
  267. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine.egg-info/entry_points.txt +0 -0
  268. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine.egg-info/requires.txt +0 -0
  269. {frontengine-1.0.48 → frontengine-1.0.50}/frontengine.egg-info/top_level.txt +0 -0
  270. {frontengine-1.0.48 → frontengine-1.0.50}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.48
3
+ Version: 1.0.50
4
4
  Summary: FrontEngine is use-define frontview or only use like screen saver
5
5
  Author-email: JE-Chen <jechenmailman@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/Intergration-Automation-Testing/FrontEngine
@@ -185,25 +185,6 @@ that caps every overlay's refresh rate and drops its render resolution.
185
185
 
186
186
  ---
187
187
 
188
- ## Stream and gaming
189
-
190
- Four things on the **Stream** tab, for playing and for going live:
191
-
192
- - **Crosshair** — a cross, dot, circle or T shape in the middle of the screen,
193
- in your colour and size. It is **only drawn on top**: nothing is injected,
194
- no memory is read, no game file is touched. An exclusive-fullscreen game will
195
- cover it, which is how the OS stacks windows.
196
- - **Teleprompter** — scroll a script at an adjustable speed and size, with a
197
- mirror option for prompter glass. It stops at the last line rather than
198
- snapping back mid-read.
199
- - **Soundboard** — up to twelve slots, each with a sound and an optional
200
- hotkey. A file that has gone missing is dropped rather than kept as a dead
201
- button.
202
- - **OBS** — switch scenes and toggle recording or streaming through OBS's own
203
- WebSocket (built in since OBS 28). The password stays in your local settings.
204
-
205
- ---
206
-
207
188
  ## Signage, whiteboard and lip-sync
208
189
 
209
190
  - **Signage mode** (Settings) — rotate through a list of presets on a timer and
@@ -161,25 +161,6 @@ that caps every overlay's refresh rate and drops its render resolution.
161
161
 
162
162
  ---
163
163
 
164
- ## Stream and gaming
165
-
166
- Four things on the **Stream** tab, for playing and for going live:
167
-
168
- - **Crosshair** — a cross, dot, circle or T shape in the middle of the screen,
169
- in your colour and size. It is **only drawn on top**: nothing is injected,
170
- no memory is read, no game file is touched. An exclusive-fullscreen game will
171
- cover it, which is how the OS stacks windows.
172
- - **Teleprompter** — scroll a script at an adjustable speed and size, with a
173
- mirror option for prompter glass. It stops at the last line rather than
174
- snapping back mid-read.
175
- - **Soundboard** — up to twelve slots, each with a sound and an optional
176
- hotkey. A file that has gone missing is dropped rather than kept as a dead
177
- button.
178
- - **OBS** — switch scenes and toggle recording or streaming through OBS's own
179
- WebSocket (built in since OBS 28). The password stays in your local settings.
180
-
181
- ---
182
-
183
164
  ## Signage, whiteboard and lip-sync
184
165
 
185
166
  - **Signage mode** (Settings) — rotate through a list of presets on a timer and
@@ -2,7 +2,7 @@ import os
2
2
  import sys
3
3
  from os import getcwd
4
4
  from pathlib import Path
5
- from typing import Dict, Optional, Type
5
+ from typing import Any, Dict, Optional, Type
6
6
 
7
7
  from PySide6.QtCore import QByteArray, QTimer, QCoreApplication
8
8
  from PySide6.QtGui import QIcon, Qt
@@ -29,7 +29,6 @@ from frontengine.ui.page.scene_setting.scene_setting_ui import SceneSettingUI
29
29
  from frontengine.ui.page.presentation.presentation_setting_ui import PresentationSettingUI
30
30
  from frontengine.ui.page.screen_care.screen_care_setting_ui import ScreenCareSettingUI
31
31
  from frontengine.ui.page.sound_player.sound_player_setting_ui import SoundPlayerSettingUI
32
- from frontengine.ui.page.stream.stream_setting_ui import StreamSettingUI
33
32
  from frontengine.ui.page.text.text_setting_ui import TextSettingUI
34
33
  from frontengine.ui.page.tools.tools_setting_ui import ToolsSettingUI
35
34
  from frontengine.ui.page.video.video_setting_ui import VideoSettingUI
@@ -74,6 +73,20 @@ from frontengine.utils.theme_schedule.theme_schedule_service import ThemeSchedul
74
73
  FrontEngine_EXTEND_TAB: Dict[str, Type[QWidget]] = {}
75
74
 
76
75
 
76
+ def tray_can_restore_window(window: Any) -> bool:
77
+ """
78
+ 系統匣能不能把主視窗叫回來。任何「把主視窗藏起來」的功能都得先問這件事,
79
+ 不然藏掉的就是唯一能把該功能關掉的畫面。
80
+ Whether the tray can bring the main window back. Anything that hides the
81
+ window has to ask first: otherwise what it hides is the only screen that
82
+ can turn that same thing off.
83
+ """
84
+ tray = getattr(window, "system_tray", None)
85
+ return bool(ExtendSystemTray.isSystemTrayAvailable()
86
+ and getattr(window, "show_system_tray_ray", False)
87
+ and tray is not None and tray.isVisible())
88
+
89
+
77
90
  class FrontEngineMainUI(QMainWindow):
78
91
  """
79
92
  FrontEngine 主視窗
@@ -136,7 +149,6 @@ class FrontEngineMainUI(QMainWindow):
136
149
  self.focus_setting_ui = FocusSettingUI()
137
150
  self.widgets_setting_ui = WidgetsSettingUI()
138
151
  self.tools_setting_ui = ToolsSettingUI()
139
- self.stream_setting_ui = StreamSettingUI()
140
152
 
141
153
  # 控制中心
142
154
  # Control Center
@@ -321,9 +333,10 @@ class FrontEngineMainUI(QMainWindow):
321
333
  """
322
334
  sources = (
323
335
  (self.screen_care_setting_ui, ("filter_widget_list", "ruler_widget_list",
324
- "break_overlay_list")),
336
+ "break_overlay_list", "color_vision_widget_list")),
325
337
  (self.presentation_setting_ui, ("annotation_widget_list", "cursor_widget_list",
326
- "keystroke_widget_list", "magnifier_widget_list")),
338
+ "keystroke_widget_list", "magnifier_widget_list",
339
+ "whiteboard_widget_list")),
327
340
  (self.focus_setting_ui, ("dim_widget_list", "mask_widget_list")),
328
341
  )
329
342
  for page, attributes in sources:
@@ -334,6 +347,12 @@ class FrontEngineMainUI(QMainWindow):
334
347
  # The wallpaper page keys its widgets by monitor, so hand over the values.
335
348
  self.control_center_ui.register_overlay_source(
336
349
  lambda: list(self.wallpaper_setting_ui.wallpaper_widgets.values()))
350
+ self.control_center_ui.register_overlay_source(
351
+ lambda: getattr(self.web_setting_ui, "dashboard_widgets", []))
352
+ # 批次關閉之後,沒有覆蓋層在聽就把全域輸入監聽收掉
353
+ # After a batch close nothing is listening, so drop the global input hook.
354
+ self.control_center_ui.register_cleanup(
355
+ self.presentation_setting_ui.release_input_watch)
337
356
  for attribute in ("spectrum_widget_list", "monitor_widget_list",
338
357
  "now_playing_widget_list", "note_widget_list"):
339
358
  self.control_center_ui.register_overlay_source(
@@ -341,9 +360,6 @@ class FrontEngineMainUI(QMainWindow):
341
360
  for attribute in ("measure_widget_list", "capture_widget_list", "camera_widget_list"):
342
361
  self.control_center_ui.register_overlay_source(
343
362
  lambda attribute=attribute: getattr(self.tools_setting_ui, attribute, []))
344
- for attribute in ("crosshair_widget_list", "teleprompter_widget_list"):
345
- self.control_center_ui.register_overlay_source(
346
- lambda attribute=attribute: getattr(self.stream_setting_ui, attribute, []))
347
363
 
348
364
  def _add_tabs(self) -> None:
349
365
  """加入所有內建與擴充的 Tab / Add all built-in and extended tabs"""
@@ -363,7 +379,6 @@ class FrontEngineMainUI(QMainWindow):
363
379
  (self.focus_setting_ui, "tab_focus_text"),
364
380
  (self.widgets_setting_ui, "tab_widgets_text"),
365
381
  (self.tools_setting_ui, "tab_tools_text"),
366
- (self.stream_setting_ui, "tab_stream_text"),
367
382
  (self.control_center_ui, "tab_control_center_text"),
368
383
  ]
369
384
 
@@ -518,12 +533,28 @@ class FrontEngineMainUI(QMainWindow):
518
533
  self._handle_hotkey(action)
519
534
 
520
535
  def start_signage(self) -> Optional[str]:
521
- """開始輪播;設定要求的話也把主視窗收起來。"""
536
+ """開始輪播;設定要求、而且托盤能把視窗叫回來時才收起主視窗。"""
522
537
  first = self.signage_service.start()
523
538
  if first is not None and current_signage_settings().get("hide_window", True):
524
- self.hide()
539
+ self._hide_for_signage()
525
540
  return first
526
541
 
542
+ def _hide_for_signage(self) -> None:
543
+ """
544
+ 收起主視窗——但只在系統匣真的能把它叫回來的時候。沒有系統匣就等於
545
+ 把唯一能關掉輪播的畫面藏起來,重開也只會再被藏一次,使用者就只能去
546
+ 手動改設定檔了。
547
+ Put the main window away - but only when the tray can actually bring it
548
+ back. Without a tray this would hide the only screen that can turn the
549
+ rotation off, and restarting just hides it again, leaving the settings
550
+ file as the only way out.
551
+ """
552
+ if tray_can_restore_window(self):
553
+ self.hide()
554
+ return
555
+ front_engine_logger.info(
556
+ "[FrontEngineMainUI] signage kept the window visible: no tray to restore it from")
557
+
527
558
  def stop_signage(self) -> None:
528
559
  """停止輪播並把主視窗放回來。"""
529
560
  self.signage_service.stop()
@@ -644,8 +675,6 @@ class FrontEngineMainUI(QMainWindow):
644
675
  self.tools_setting_ui.release_pinned_windows()
645
676
  self.tools_setting_ui.stop_camera()
646
677
  self.tools_setting_ui.stop_virtual_camera()
647
- if getattr(self, "stream_setting_ui", None) is not None:
648
- self.stream_setting_ui.soundboard.stop_all()
649
678
 
650
679
  def _clear_overlays(self) -> None:
651
680
  """清空各分頁記著的覆蓋層清單。"""
@@ -1,3 +1,5 @@
1
+ from typing import Callable
2
+
1
3
  from PySide6.QtCore import QTimer, Qt
2
4
  from PySide6.QtWidgets import (
3
5
  QComboBox, QGridLayout, QLabel, QPushButton, QScrollArea, QTextEdit, QWidget,
@@ -93,6 +95,7 @@ class ControlCenterUI(QWidget):
93
95
  # 其他分頁登記進來的覆蓋層來源(桌布、專注、護眼、簡報…)
94
96
  # Overlay sources registered by the other pages: wallpaper, focus, screen care, presenting.
95
97
  self._extra_overlay_sources: list = []
98
+ self._cleanup_callbacks: list = []
96
99
  self.low_power_button = self._create_button(
97
100
  "control_center_low_power_on", self.toggle_low_power)
98
101
  self._hidden_from_capture = False
@@ -190,19 +193,29 @@ class ControlCenterUI(QWidget):
190
193
  self.scene_setting_ui.close_scene()
191
194
 
192
195
  def clear_all(self) -> None:
196
+ """
197
+ 關閉所有覆蓋層。先真的 close() 再清空清單:close() 會跑到 closeEvent,
198
+ 計時器、媒體、全域監聽才停得掉;只丟掉 Python 參考做不到這件事,而且
199
+ 對「其他分頁註冊進來的」覆蓋層根本沒作用——它們會留在螢幕上。
200
+ Close every overlay. Actually call close() before emptying the lists:
201
+ that runs closeEvent, which is what stops timers, releases media and
202
+ drops global listeners. Merely dropping a Python reference does none of
203
+ that, and for the overlays other pages registered it did nothing at all
204
+ - they stayed on screen.
205
+ """
193
206
  front_engine_logger.info("ControlCenterUI clear_all")
194
- self.video_setting_ui.video_widget_list.clear()
195
- self.image_setting_ui.image_widget_list.clear()
196
- self.web_setting_ui.web_widget_list.clear()
197
- self.gif_setting_ui.gif_widget_list.clear()
198
- self.sound_player_setting_ui.sound_widget_list.clear()
199
- self.text_setting_ui.text_widget_list.clear()
200
- self.particle_setting_ui.particle_list.clear()
201
- if self.pet_setting_ui is not None:
202
- self.pet_setting_ui.pet_list.clear()
207
+ self._for_each_overlay(lambda widget: widget.close())
208
+ for widget_list in self._all_overlay_widget_lists():
209
+ widget_list.clear()
203
210
  self.scene_setting_ui.close_scene()
211
+ for callback in self._cleanup_callbacks:
212
+ try:
213
+ callback()
214
+ except Exception as error:
215
+ front_engine_logger.warning(
216
+ f"[ControlCenterUI] cleanup failed: {error!r}")
204
217
 
205
- def register_overlay_source(self, provider) -> None:
218
+ def register_overlay_source(self, provider: Callable[[], list]) -> None:
206
219
  """
207
220
  讓控制中心也管得到其他分頁開的覆蓋層。provider 是一個回傳 widget 清單
208
221
  的函式(每次都重新問,才拿得到當下還活著的那些)。
@@ -212,6 +225,16 @@ class ControlCenterUI(QWidget):
212
225
  """
213
226
  self._extra_overlay_sources.append(provider)
214
227
 
228
+ def register_cleanup(self, callback: Callable[[], None]) -> None:
229
+ """
230
+ 批次關閉之後要順手收掉的東西。例如全域輸入監聽:覆蓋層都關掉了就
231
+ 沒有東西需要它,繼續掛著只是白吃資源。
232
+ Something to release after a batch close - a global input listener,
233
+ say: with every overlay gone nothing needs it, and leaving it hooked
234
+ just costs for nothing.
235
+ """
236
+ self._cleanup_callbacks.append(callback)
237
+
215
238
  def _all_overlay_widget_lists(self) -> list:
216
239
  """回傳所有覆蓋層 widget 清單 / All overlay widget lists."""
217
240
  lists = [
@@ -231,11 +254,15 @@ class ControlCenterUI(QWidget):
231
254
  except Exception as error: # pragma: no cover - defensive boundary
232
255
  front_engine_logger.warning(f"[ControlCenterUI] overlay source failed: {error!r}")
233
256
  continue
257
+ # 交回原本的清單物件(不是複本),死掉的參考才清得掉、
258
+ # 「全部關閉」也才真的能把它們清空。
259
+ # Hand back the provider's own list rather than a copy, so pruning
260
+ # a dead reference - and closing everything - reaches the real one.
234
261
  if widgets:
235
- lists.append(list(widgets))
262
+ lists.append(widgets if isinstance(widgets, list) else list(widgets))
236
263
  return lists
237
264
 
238
- def _for_each_overlay(self, action) -> None:
265
+ def _for_each_overlay(self, action: Callable[[QWidget], None]) -> None:
239
266
  """
240
267
  對每個仍存活的覆蓋層 widget 執行 action(widget)。手動關閉的覆蓋層因
241
268
  WA_DeleteOnClose 已被銷毀,其 Python 參考仍留在清單中,呼叫時會
@@ -6,7 +6,7 @@ The presentation page: screen annotation, cursor emphasis (ring, click ripple,
6
6
  spotlight), a keystroke display and a region magnifier. Everything except the
7
7
  annotation layer passes clicks straight through.
8
8
  """
9
- from typing import List
9
+ from typing import List, Optional
10
10
 
11
11
  from PySide6.QtCore import Qt
12
12
  from PySide6.QtGui import QGuiApplication
@@ -181,7 +181,8 @@ class PresentationSettingUI(QWidget):
181
181
  if self.keystroke_widget_list or self.cursor_widget_list:
182
182
  self.input_watch.start()
183
183
 
184
- def _release_input_watch(self) -> None:
184
+ def release_input_watch(self) -> None:
185
+ """沒有覆蓋層要聽了就收掉全域輸入監聽(批次關閉之後也會呼叫)。"""
185
186
  if not self.keystroke_widget_list and not self.cursor_widget_list:
186
187
  self.input_watch.stop()
187
188
 
@@ -250,7 +251,7 @@ class PresentationSettingUI(QWidget):
250
251
 
251
252
  def stop_cursor_effects(self) -> None:
252
253
  self._close_all(self.cursor_widget_list)
253
- self._release_input_watch()
254
+ self.release_input_watch()
254
255
  self.cursor_button.setText(
255
256
  language_wrapper.language_word_dict.get("cursor_effect_start", "Turn cursor effects on"))
256
257
 
@@ -285,7 +286,7 @@ class PresentationSettingUI(QWidget):
285
286
 
286
287
  def stop_keystrokes(self) -> None:
287
288
  self._close_all(self.keystroke_widget_list)
288
- self._release_input_watch()
289
+ self.release_input_watch()
289
290
  self.keystroke_button.setText(
290
291
  language_wrapper.language_word_dict.get("keystroke_start", "Show keystrokes"))
291
292
 
@@ -341,7 +342,6 @@ class PresentationSettingUI(QWidget):
341
342
  except RuntimeError:
342
343
  self.magnifier_widget_list.remove(widget)
343
344
 
344
- # --- preset state ----------------------------------------------------
345
345
  # --- whiteboard ------------------------------------------------------
346
346
  def toggle_whiteboard(self) -> None:
347
347
  if self.whiteboard_widget_list:
@@ -364,7 +364,7 @@ class PresentationSettingUI(QWidget):
364
364
  self.whiteboard_button.setText(
365
365
  language_wrapper.language_word_dict.get("whiteboard_start", "Whiteboard"))
366
366
 
367
- def save_whiteboard(self):
367
+ def save_whiteboard(self) -> Optional[str]:
368
368
  """把白板存成圖片;沒畫東西就不存。"""
369
369
  for board in self.whiteboard_widget_list[:]:
370
370
  try:
@@ -377,6 +377,7 @@ class PresentationSettingUI(QWidget):
377
377
  self.whiteboard_widget_list.remove(board)
378
378
  return None
379
379
 
380
+ # --- preset state ----------------------------------------------------
380
381
  def get_state(self) -> dict:
381
382
  return {
382
383
  "annotate_tool": self.annotate_tool_combobox.currentData(),
@@ -81,12 +81,6 @@ user_setting_dict: Dict[str, Any] = {
81
81
  # 是否同意把擷取畫面送到 Anthropic 讀取文字(預設不同意)
82
82
  # Consent to send captures to Anthropic for reading text (off by default).
83
83
  "screen_text_consent": False,
84
- # 音效板:[{label, path, hotkey, volume}]
85
- # Soundboard slots: [{label, path, hotkey, volume}]
86
- "soundboard": [],
87
- # OBS WebSocket 連線設定(密碼只留在本機設定檔)
88
- # OBS WebSocket connection; the password stays in the local settings file.
89
- "obs": {"host": "127.0.0.1", "port": 4455, "password": "", "scene": ""},
90
84
  # 覆蓋層畫質檔位:high / balanced / saver
91
85
  # Overlay quality tier: high / balanced / saver.
92
86
  "quality_tier": "high",
@@ -518,30 +518,6 @@ english_word_dict = {
518
518
  "screen_text_consent_body": "Reading text needs the captured area sent to Anthropic's API. It leaves this machine, and anything visible in the selection goes with it. Your own ANTHROPIC_API_KEY is used. Send captures?",
519
519
  "screen_text_no_key": 'Set {env} in your environment to use this.',
520
520
  "screen_text_ready": 'Captures are sent to Anthropic only while the box above is ticked.',
521
- "tab_stream_text": 'Stream',
522
- "stream_crosshair_label": 'Crosshair',
523
- "stream_crosshair_cross": 'Cross',
524
- "stream_crosshair_dot": 'Dot',
525
- "stream_crosshair_circle": 'Circle',
526
- "stream_crosshair_t": 'T shape',
527
- "stream_crosshair_start": 'Show crosshair',
528
- "stream_crosshair_stop": 'Hide crosshair',
529
- "stream_teleprompter_label": 'Teleprompter',
530
- "stream_teleprompter_script": 'Paste your script here',
531
- "stream_teleprompter_mirror": 'Mirror',
532
- "stream_teleprompter_start": 'Start prompter',
533
- "stream_teleprompter_stop": 'Stop prompter',
534
- "stream_sound_label": 'Soundboard',
535
- "stream_sound_add": 'Add sound',
536
- "stream_sound_remove": 'Remove',
537
- "stream_sound_play": 'Play',
538
- "stream_obs_label": 'OBS',
539
- "stream_obs_password": 'WebSocket password', # NOSONAR - a field label, not a credential
540
- "stream_obs_scene": 'Scene name',
541
- "stream_obs_switch": 'Switch scene',
542
- "stream_obs_record": 'Toggle recording',
543
- "stream_obs_stream": 'Toggle streaming',
544
- "stream_hint": 'The crosshair is only drawn on top - no game is modified. OBS control uses its own WebSocket; the password is kept in your local settings.',
545
521
  "control_center_hide_from_capture": 'Hide from capture',
546
522
  "control_center_show_in_capture": 'Show in capture',
547
523
  "settings_menu_screen_privacy": 'Screen-sharing privacy...',
@@ -517,30 +517,6 @@ traditional_chinese_word_dict = {
517
517
  "screen_text_consent_body": '讀取文字需要把框選到的畫面送到 Anthropic 的 API。這份畫面會離開這台電腦,框選範圍內看得到的東西都會一起送出,使用的是你自己的 ANTHROPIC_API_KEY。要送出嗎?',
518
518
  "screen_text_no_key": '請先在環境變數設定 {env} 才能使用。',
519
519
  "screen_text_ready": '只有在上面那個選項打勾時,擷取畫面才會送到 Anthropic。',
520
- "tab_stream_text": '直播',
521
- "stream_crosshair_label": '準星',
522
- "stream_crosshair_cross": '十字',
523
- "stream_crosshair_dot": '點',
524
- "stream_crosshair_circle": '圓環',
525
- "stream_crosshair_t": 'T 字',
526
- "stream_crosshair_start": '顯示準星',
527
- "stream_crosshair_stop": '關閉準星',
528
- "stream_teleprompter_label": '提詞機',
529
- "stream_teleprompter_script": '把講稿貼在這裡',
530
- "stream_teleprompter_mirror": '左右鏡像',
531
- "stream_teleprompter_start": '開始提詞',
532
- "stream_teleprompter_stop": '停止提詞',
533
- "stream_sound_label": '音效板',
534
- "stream_sound_add": '新增音效',
535
- "stream_sound_remove": '移除',
536
- "stream_sound_play": '播放',
537
- "stream_obs_label": 'OBS',
538
- "stream_obs_password": 'WebSocket 密碼', # NOSONAR - a field label, not a credential
539
- "stream_obs_scene": '場景名稱',
540
- "stream_obs_switch": '切換場景',
541
- "stream_obs_record": '切換錄影',
542
- "stream_obs_stream": '切換直播',
543
- "stream_hint": '準星只是疊在畫面上的一層,不會更動任何遊戲。OBS 控制走它自己的 WebSocket,密碼只留在本機設定檔裡。',
544
520
  "control_center_hide_from_capture": '分享時隱藏',
545
521
  "control_center_show_in_capture": '分享時顯示',
546
522
  "settings_menu_screen_privacy": '螢幕分享隱私…',
@@ -24,7 +24,7 @@ import secrets
24
24
  import socket
25
25
  import threading
26
26
  from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
27
- from typing import Any, Dict, List, Optional, Tuple
27
+ from typing import Any, Dict, Optional, Tuple
28
28
  from urllib.parse import parse_qs, urlparse
29
29
 
30
30
  from PySide6.QtCore import QObject, Signal
@@ -138,7 +138,6 @@ class RemoteServer(QObject):
138
138
  self._on_action = on_action
139
139
  self._server: Optional[ThreadingHTTPServer] = None
140
140
  self._thread: Optional[threading.Thread] = None
141
- self.received: List[str] = []
142
141
 
143
142
  @property
144
143
  def running(self) -> bool:
@@ -192,7 +191,6 @@ class RemoteServer(QObject):
192
191
  return 403
193
192
  if not is_allowed(action):
194
193
  return 400
195
- self.received.append(str(action))
196
194
  self.action_requested.emit(str(action))
197
195
  if self._on_action is not None:
198
196
  self._on_action(str(action))
@@ -22,10 +22,13 @@ determined attacker, and it never hides the window from the person at the desk.
22
22
  from __future__ import annotations
23
23
 
24
24
  import sys
25
- from typing import Optional
25
+ from typing import TYPE_CHECKING, Iterable, Optional
26
26
 
27
27
  from frontengine.utils.logging.loggin_instance import front_engine_logger
28
28
 
29
+ if TYPE_CHECKING: # 只為了型別標註,執行時不需要把 Qt 拉進這支純 ctypes 工具
30
+ from PySide6.QtWidgets import QWidget
31
+
29
32
  # WDA_NONE:正常擷取;WDA_EXCLUDEFROMCAPTURE:擷取時整片留白
30
33
  # WDA_NONE captures normally; WDA_EXCLUDEFROMCAPTURE comes out blank.
31
34
  WDA_NONE = 0x00000000
@@ -92,7 +95,7 @@ def is_excluded_from_capture(handle: int) -> Optional[bool]:
92
95
  return None
93
96
 
94
97
 
95
- def apply_to_widget(widget, excluded: bool) -> bool:
98
+ def apply_to_widget(widget: Optional[QWidget], excluded: bool) -> bool:
96
99
  """
97
100
  對一個 Qt widget 套用擷取可見性。視窗還沒建立原生 handle 時回傳 False,
98
101
  呼叫端可以等 show() 之後再試一次。
@@ -108,7 +111,7 @@ def apply_to_widget(widget, excluded: bool) -> bool:
108
111
  return set_excluded_from_capture(handle, excluded)
109
112
 
110
113
 
111
- def apply_to_widgets(widgets, excluded: bool) -> int:
114
+ def apply_to_widgets(widgets: Optional[Iterable[QWidget]], excluded: bool) -> int:
112
115
  """對一批 widget 套用,回傳成功的數量。"""
113
116
  applied = 0
114
117
  for widget in tuple(widgets or ()):
@@ -46,7 +46,7 @@ class VirtualCameraFeed(QObject):
46
46
  return None
47
47
  return screen.grabWindow(0, rect.x(), rect.y(), rect.width(), rect.height())
48
48
 
49
- def set_grabber(self, grabber) -> None:
49
+ def set_grabber(self, grabber: Optional[Callable[[QRect], Optional[QPixmap]]]) -> None:
50
50
  self._grabber = grabber or self._default_grabber
51
51
 
52
52
  def start(self, region: QRect, fps: int) -> bool:
@@ -15,7 +15,7 @@ False and the feature stays off; nothing is ever sent quietly.
15
15
  """
16
16
  from __future__ import annotations
17
17
 
18
- from typing import Optional, Tuple
18
+ from typing import Any, Optional, Tuple
19
19
 
20
20
  import numpy
21
21
 
@@ -47,7 +47,7 @@ def available() -> bool:
47
47
  return _module() is not None
48
48
 
49
49
 
50
- def clamp_fps(value, fallback: int = DEFAULT_FPS) -> int:
50
+ def clamp_fps(value: Any, fallback: int = DEFAULT_FPS) -> int:
51
51
  """每秒張數夾在驅動接受的範圍。"""
52
52
  try:
53
53
  return max(MIN_FPS, min(MAX_FPS, int(value)))
@@ -55,9 +55,9 @@ def clamp_fps(value, fallback: int = DEFAULT_FPS) -> int:
55
55
  return fallback
56
56
 
57
57
 
58
- def even_size(width, height) -> Tuple[int, int]:
58
+ def even_size(width: Any, height: Any) -> Tuple[int, int]:
59
59
  """把尺寸調成偶數且不小於 2x2。"""
60
- def fix(value, fallback):
60
+ def fix(value: Any, fallback: int) -> int:
61
61
  try:
62
62
  number = max(_SIZE_STEP, int(value))
63
63
  except (TypeError, ValueError):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.48
3
+ Version: 1.0.50
4
4
  Summary: FrontEngine is use-define frontview or only use like screen saver
5
5
  Author-email: JE-Chen <jechenmailman@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/Intergration-Automation-Testing/FrontEngine
@@ -185,25 +185,6 @@ that caps every overlay's refresh rate and drops its render resolution.
185
185
 
186
186
  ---
187
187
 
188
- ## Stream and gaming
189
-
190
- Four things on the **Stream** tab, for playing and for going live:
191
-
192
- - **Crosshair** — a cross, dot, circle or T shape in the middle of the screen,
193
- in your colour and size. It is **only drawn on top**: nothing is injected,
194
- no memory is read, no game file is touched. An exclusive-fullscreen game will
195
- cover it, which is how the OS stacks windows.
196
- - **Teleprompter** — scroll a script at an adjustable speed and size, with a
197
- mirror option for prompter glass. It stops at the last line rather than
198
- snapping back mid-read.
199
- - **Soundboard** — up to twelve slots, each with a sound and an optional
200
- hotkey. A file that has gone missing is dropped rather than kept as a dead
201
- button.
202
- - **OBS** — switch scenes and toggle recording or streaming through OBS's own
203
- WebSocket (built in since OBS 28). The password stays in your local settings.
204
-
205
- ---
206
-
207
188
  ## Signage, whiteboard and lip-sync
208
189
 
209
190
  - **Signage mode** (Settings) — rotate through a list of presets on a timer and
@@ -21,8 +21,6 @@ frontengine/show/capture/__init__.py
21
21
  frontengine/show/capture/region_capture.py
22
22
  frontengine/show/focus_shield/__init__.py
23
23
  frontengine/show/focus_shield/focus_shield_widget.py
24
- frontengine/show/gaming/__init__.py
25
- frontengine/show/gaming/crosshair_widget.py
26
24
  frontengine/show/gif/__init__.py
27
25
  frontengine/show/gif/paint_gif.py
28
26
  frontengine/show/image/__init__.py
@@ -56,8 +54,6 @@ frontengine/show/sound_player/sound_effect.py
56
54
  frontengine/show/sound_player/sound_player.py
57
55
  frontengine/show/spectrum/__init__.py
58
56
  frontengine/show/spectrum/spectrum_widget.py
59
- frontengine/show/teleprompter/__init__.py
60
- frontengine/show/teleprompter/teleprompter_widget.py
61
57
  frontengine/show/text/__init__.py
62
58
  frontengine/show/text/draw_text.py
63
59
  frontengine/show/toast/__init__.py
@@ -126,8 +122,6 @@ frontengine/ui/page/screen_care/__init__.py
126
122
  frontengine/ui/page/screen_care/screen_care_setting_ui.py
127
123
  frontengine/ui/page/sound_player/__init__.py
128
124
  frontengine/ui/page/sound_player/sound_player_setting_ui.py
129
- frontengine/ui/page/stream/__init__.py
130
- frontengine/ui/page/stream/stream_setting_ui.py
131
125
  frontengine/ui/page/text/__init__.py
132
126
  frontengine/ui/page/text/text_setting_ui.py
133
127
  frontengine/ui/page/tools/__init__.py
@@ -208,10 +202,6 @@ frontengine/utils/multi_language/simplified_chinese.py
208
202
  frontengine/utils/multi_language/traditional_chinese.py
209
203
  frontengine/utils/now_playing/__init__.py
210
204
  frontengine/utils/now_playing/now_playing.py
211
- frontengine/utils/obs/__init__.py
212
- frontengine/utils/obs/obs_client.py
213
- frontengine/utils/obs/obs_protocol.py
214
- frontengine/utils/obs/websocket_frames.py
215
205
  frontengine/utils/pet_chat/__init__.py
216
206
  frontengine/utils/pet_chat/pet_chat_service.py
217
207
  frontengine/utils/platform_info/__init__.py
@@ -243,8 +233,6 @@ frontengine/utils/signage/signage_service.py
243
233
  frontengine/utils/smart_pause/__init__.py
244
234
  frontengine/utils/smart_pause/pause_rules.py
245
235
  frontengine/utils/smart_pause/smart_pause_service.py
246
- frontengine/utils/soundboard/__init__.py
247
- frontengine/utils/soundboard/soundboard.py
248
236
  frontengine/utils/system_stats/__init__.py
249
237
  frontengine/utils/system_stats/system_stats.py
250
238
  frontengine/utils/text_source/__init__.py
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "frontengine"
9
- version = "1.0.48"
9
+ version = "1.0.50"
10
10
  authors = [
11
11
  { name = "JE-Chen", email = "jechenmailman@gmail.com" },
12
12
  ]