pumaguard 21.post27__py3-none-any.whl → 21.post83__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. pumaguard/presets.py +1 -0
  2. pumaguard/pumaguard-ui/.last_build_id +1 -1
  3. pumaguard/pumaguard-ui/assets/NOTICES +621 -71
  4. pumaguard/pumaguard-ui/assets/fonts/MaterialIcons-Regular.otf +0 -0
  5. pumaguard/pumaguard-ui/flutter_bootstrap.js +1 -1
  6. pumaguard/pumaguard-ui/main.dart.js +28869 -28787
  7. pumaguard/web_routes/dhcp.py +311 -54
  8. pumaguard/web_routes/diagnostics.py +6 -0
  9. pumaguard/web_routes/settings.py +13 -0
  10. pumaguard/web_ui.py +29 -0
  11. {pumaguard-21.post27.dist-info → pumaguard-21.post83.dist-info}/METADATA +1 -1
  12. pumaguard-21.post83.dist-info/RECORD +254 -0
  13. pumaguard-ui/.gitignore +48 -0
  14. pumaguard-ui/.metadata +45 -0
  15. pumaguard-ui/API_REFERENCE.md +717 -0
  16. pumaguard-ui/LICENSE +201 -0
  17. pumaguard-ui/Makefile +36 -0
  18. pumaguard-ui/README.md +371 -0
  19. pumaguard-ui/UI_DEVELOPMENT_CONTEXT.md +427 -0
  20. pumaguard-ui/analysis_options.yaml +28 -0
  21. pumaguard-ui/android/.gitignore +14 -0
  22. pumaguard-ui/android/app/build.gradle.kts +44 -0
  23. pumaguard-ui/android/app/src/debug/AndroidManifest.xml +7 -0
  24. pumaguard-ui/android/app/src/main/AndroidManifest.xml +45 -0
  25. pumaguard-ui/android/app/src/main/kotlin/com/example/pumaguard_ui/MainActivity.kt +5 -0
  26. pumaguard-ui/android/app/src/main/res/drawable/launch_background.xml +12 -0
  27. pumaguard-ui/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
  28. pumaguard-ui/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  29. pumaguard-ui/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  30. pumaguard-ui/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  31. pumaguard-ui/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  32. pumaguard-ui/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  33. pumaguard-ui/android/app/src/main/res/values/styles.xml +18 -0
  34. pumaguard-ui/android/app/src/main/res/values-night/styles.xml +18 -0
  35. pumaguard-ui/android/app/src/profile/AndroidManifest.xml +7 -0
  36. pumaguard-ui/android/build.gradle.kts +24 -0
  37. pumaguard-ui/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  38. pumaguard-ui/android/gradle.properties +2 -0
  39. pumaguard-ui/android/settings.gradle.kts +26 -0
  40. pumaguard-ui/fonts/README.md +38 -0
  41. pumaguard-ui/fonts/Roboto-Bold.ttf +0 -0
  42. pumaguard-ui/fonts/Roboto-Light.ttf +0 -0
  43. pumaguard-ui/fonts/Roboto-Medium.ttf +0 -0
  44. pumaguard-ui/fonts/Roboto-Regular.ttf +0 -0
  45. pumaguard-ui/fonts/RobotoMono-Bold.ttf +0 -0
  46. pumaguard-ui/fonts/RobotoMono-Medium.ttf +0 -0
  47. pumaguard-ui/fonts/RobotoMono-Regular.ttf +0 -0
  48. pumaguard-ui/fonts/download_fonts.sh +76 -0
  49. pumaguard-ui/ios/.gitignore +34 -0
  50. pumaguard-ui/ios/Flutter/AppFrameworkInfo.plist +26 -0
  51. pumaguard-ui/ios/Flutter/Debug.xcconfig +1 -0
  52. pumaguard-ui/ios/Flutter/Release.xcconfig +1 -0
  53. pumaguard-ui/ios/Runner/AppDelegate.swift +13 -0
  54. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +122 -0
  55. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png +0 -0
  56. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png +0 -0
  57. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png +0 -0
  58. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png +0 -0
  59. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png +0 -0
  60. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png +0 -0
  61. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png +0 -0
  62. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png +0 -0
  63. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png +0 -0
  64. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png +0 -0
  65. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png +0 -0
  66. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png +0 -0
  67. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png +0 -0
  68. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png +0 -0
  69. pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png +0 -0
  70. pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +23 -0
  71. pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png +0 -0
  72. pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png +0 -0
  73. pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png +0 -0
  74. pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +5 -0
  75. pumaguard-ui/ios/Runner/Base.lproj/LaunchScreen.storyboard +37 -0
  76. pumaguard-ui/ios/Runner/Base.lproj/Main.storyboard +26 -0
  77. pumaguard-ui/ios/Runner/Info.plist +49 -0
  78. pumaguard-ui/ios/Runner/Runner-Bridging-Header.h +1 -0
  79. pumaguard-ui/ios/Runner.xcodeproj/project.pbxproj +616 -0
  80. pumaguard-ui/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  81. pumaguard-ui/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  82. pumaguard-ui/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  83. pumaguard-ui/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +101 -0
  84. pumaguard-ui/ios/Runner.xcworkspace/contents.xcworkspacedata +7 -0
  85. pumaguard-ui/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  86. pumaguard-ui/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  87. pumaguard-ui/ios/RunnerTests/RunnerTests.swift +12 -0
  88. pumaguard-ui/lib/main.dart +56 -0
  89. pumaguard-ui/lib/models/camera.dart +45 -0
  90. pumaguard-ui/lib/models/plug.dart +45 -0
  91. pumaguard-ui/lib/models/settings.dart +112 -0
  92. pumaguard-ui/lib/models/status.dart +58 -0
  93. pumaguard-ui/lib/screens/directories_screen.dart +319 -0
  94. pumaguard-ui/lib/screens/home_screen.dart +545 -0
  95. pumaguard-ui/lib/screens/image_browser_screen.dart +1248 -0
  96. pumaguard-ui/lib/screens/server_discovery_screen.dart +390 -0
  97. pumaguard-ui/lib/screens/settings_screen.dart +1162 -0
  98. pumaguard-ui/lib/screens/wifi_settings_screen.dart +671 -0
  99. pumaguard-ui/lib/services/api_service.dart +717 -0
  100. pumaguard-ui/lib/services/camera_events_service.dart +195 -0
  101. pumaguard-ui/lib/services/mdns_service.dart +4 -0
  102. pumaguard-ui/lib/services/mdns_service_impl.dart +282 -0
  103. pumaguard-ui/lib/services/mdns_service_io.dart +1 -0
  104. pumaguard-ui/lib/services/mdns_service_web.dart +106 -0
  105. pumaguard-ui/lib/utils/download_helper.dart +2 -0
  106. pumaguard-ui/lib/utils/download_helper_stub.dart +6 -0
  107. pumaguard-ui/lib/utils/download_helper_web.dart +14 -0
  108. pumaguard-ui/lib/utils/platform_url.dart +10 -0
  109. pumaguard-ui/lib/utils/platform_url_stub.dart +11 -0
  110. pumaguard-ui/lib/utils/platform_url_web.dart +16 -0
  111. pumaguard-ui/linux/.gitignore +1 -0
  112. pumaguard-ui/linux/CMakeLists.txt +128 -0
  113. pumaguard-ui/linux/flutter/CMakeLists.txt +88 -0
  114. pumaguard-ui/linux/flutter/generated_plugin_registrant.cc +15 -0
  115. pumaguard-ui/linux/flutter/generated_plugin_registrant.h +15 -0
  116. pumaguard-ui/linux/flutter/generated_plugins.cmake +24 -0
  117. pumaguard-ui/linux/runner/CMakeLists.txt +26 -0
  118. pumaguard-ui/linux/runner/main.cc +6 -0
  119. pumaguard-ui/linux/runner/my_application.cc +148 -0
  120. pumaguard-ui/linux/runner/my_application.h +21 -0
  121. pumaguard-ui/macos/.gitignore +7 -0
  122. pumaguard-ui/macos/Flutter/Flutter-Debug.xcconfig +1 -0
  123. pumaguard-ui/macos/Flutter/Flutter-Release.xcconfig +1 -0
  124. pumaguard-ui/macos/Flutter/GeneratedPluginRegistrant.swift +16 -0
  125. pumaguard-ui/macos/Runner/AppDelegate.swift +13 -0
  126. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
  127. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
  128. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
  129. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
  130. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
  131. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
  132. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
  133. pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
  134. pumaguard-ui/macos/Runner/Base.lproj/MainMenu.xib +343 -0
  135. pumaguard-ui/macos/Runner/Configs/AppInfo.xcconfig +14 -0
  136. pumaguard-ui/macos/Runner/Configs/Debug.xcconfig +2 -0
  137. pumaguard-ui/macos/Runner/Configs/Release.xcconfig +2 -0
  138. pumaguard-ui/macos/Runner/Configs/Warnings.xcconfig +13 -0
  139. pumaguard-ui/macos/Runner/DebugProfile.entitlements +12 -0
  140. pumaguard-ui/macos/Runner/Info.plist +32 -0
  141. pumaguard-ui/macos/Runner/MainFlutterWindow.swift +15 -0
  142. pumaguard-ui/macos/Runner/Release.entitlements +8 -0
  143. pumaguard-ui/macos/Runner.xcodeproj/project.pbxproj +705 -0
  144. pumaguard-ui/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  145. pumaguard-ui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +99 -0
  146. pumaguard-ui/macos/Runner.xcworkspace/contents.xcworkspacedata +7 -0
  147. pumaguard-ui/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  148. pumaguard-ui/macos/RunnerTests/RunnerTests.swift +12 -0
  149. pumaguard-ui/pubspec.lock +882 -0
  150. pumaguard-ui/pubspec.yaml +125 -0
  151. pumaguard-ui/test/models/camera_test.dart +515 -0
  152. pumaguard-ui/test/models/plug_test.dart +499 -0
  153. pumaguard-ui/test/models/settings_test.dart +903 -0
  154. pumaguard-ui/test/models/status_test.dart +707 -0
  155. pumaguard-ui/test/screens/image_browser_grouping_test.dart +555 -0
  156. pumaguard-ui/test/services/api_service_cameras_test.dart +580 -0
  157. pumaguard-ui/test/services/api_service_image_browser_test.dart +512 -0
  158. pumaguard-ui/test/widget_test.dart.skip +38 -0
  159. pumaguard-ui/web/favicon.png +0 -0
  160. pumaguard-ui/web/icons/Icon-192.png +0 -0
  161. pumaguard-ui/web/icons/Icon-512.png +0 -0
  162. pumaguard-ui/web/icons/Icon-maskable-192.png +0 -0
  163. pumaguard-ui/web/icons/Icon-maskable-512.png +0 -0
  164. pumaguard-ui/web/index.html +38 -0
  165. pumaguard-ui/web/manifest.json +35 -0
  166. pumaguard-ui/windows/.gitignore +17 -0
  167. pumaguard-ui/windows/CMakeLists.txt +108 -0
  168. pumaguard-ui/windows/flutter/CMakeLists.txt +109 -0
  169. pumaguard-ui/windows/flutter/generated_plugin_registrant.cc +14 -0
  170. pumaguard-ui/windows/flutter/generated_plugin_registrant.h +15 -0
  171. pumaguard-ui/windows/flutter/generated_plugins.cmake +24 -0
  172. pumaguard-ui/windows/runner/CMakeLists.txt +40 -0
  173. pumaguard-ui/windows/runner/Runner.rc +121 -0
  174. pumaguard-ui/windows/runner/flutter_window.cpp +71 -0
  175. pumaguard-ui/windows/runner/flutter_window.h +33 -0
  176. pumaguard-ui/windows/runner/main.cpp +43 -0
  177. pumaguard-ui/windows/runner/resource.h +16 -0
  178. pumaguard-ui/windows/runner/resources/app_icon.ico +0 -0
  179. pumaguard-ui/windows/runner/runner.exe.manifest +14 -0
  180. pumaguard-ui/windows/runner/utils.cpp +65 -0
  181. pumaguard-ui/windows/runner/utils.h +19 -0
  182. pumaguard-ui/windows/runner/win32_window.cpp +288 -0
  183. pumaguard-ui/windows/runner/win32_window.h +102 -0
  184. pumaguard-21.post27.dist-info/RECORD +0 -83
  185. {pumaguard-21.post27.dist-info → pumaguard-21.post83.dist-info}/WHEEL +0 -0
  186. {pumaguard-21.post27.dist-info → pumaguard-21.post83.dist-info}/entry_points.txt +0 -0
  187. {pumaguard-21.post27.dist-info → pumaguard-21.post83.dist-info}/licenses/LICENSE +0 -0
  188. {pumaguard-21.post27.dist-info → pumaguard-21.post83.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,717 @@
1
+ # PumaGuard API Reference
2
+
3
+ This document describes the REST API that the PumaGuard UI communicates with. Use this reference when developing the Flutter UI in the `pumaguard-ui` repository.
4
+
5
+ ## Base URL
6
+
7
+ The API is served by the PumaGuard Flask backend:
8
+
9
+ - **Development**: `http://localhost:5000`
10
+ - **Production**: `http://<server-ip>:5000`
11
+ - **Web UI**: Uses `Uri.base.origin` to automatically detect the current host
12
+
13
+ ## Authentication
14
+
15
+ Currently, the API does not require authentication. All endpoints are publicly accessible on the local network.
16
+
17
+ ## CORS
18
+
19
+ CORS is enabled for all origins to support web UI access from any IP/hostname.
20
+
21
+ ## API Endpoints
22
+
23
+ ### System & Status
24
+
25
+ #### GET `/api/status`
26
+
27
+ Get current server status and configuration.
28
+
29
+ **Response:**
30
+
31
+ ```json
32
+ {
33
+ "status": "running",
34
+ "version": "1.0.0",
35
+ "uptime": 3600,
36
+ "monitored_directories": ["/path/to/folder1", "/path/to/folder2"],
37
+ "total_images": 150
38
+ }
39
+ ```
40
+
41
+ **Status Codes:**
42
+
43
+ - `200 OK`: Success
44
+
45
+ ---
46
+
47
+ #### GET `/api/diagnostic`
48
+
49
+ Get detailed diagnostic information about the server.
50
+
51
+ **Response:**
52
+
53
+ ```json
54
+ {
55
+ "python_version": "3.12.0",
56
+ "tensorflow_version": "2.20.0",
57
+ "yolo_version": "8.3.0",
58
+ "system_info": {...},
59
+ "gpu_available": false
60
+ }
61
+ ```
62
+
63
+ **Status Codes:**
64
+
65
+ - `200 OK`: Success
66
+
67
+ ---
68
+
69
+ ### Settings
70
+
71
+ #### GET `/api/settings`
72
+
73
+ Get current PumaGuard settings.
74
+
75
+ **Response:**
76
+
77
+ ```json
78
+ {
79
+ "YOLO-min-size": 0.02,
80
+ "YOLO-conf-thresh": 0.25,
81
+ "YOLO-max-dets": 12,
82
+ "YOLO-model-filename": "yolov8s_101425.pt",
83
+ "classifier-model-filename": "colorbw_111325.h5",
84
+ "sound-path": "/path/to/sounds",
85
+ "deterrent-sound-file": "cougar_call.mp3",
86
+ "play-sound": true
87
+ }
88
+ ```
89
+
90
+ **Status Codes:**
91
+
92
+ - `200 OK`: Success
93
+
94
+ ---
95
+
96
+ #### PUT `/api/settings`
97
+
98
+ Update PumaGuard settings.
99
+
100
+ **Request Body:**
101
+
102
+ ```json
103
+ {
104
+ "YOLO-min-size": 0.03,
105
+ "YOLO-conf-thresh": 0.30,
106
+ "YOLO-max-dets": 15,
107
+ "play-sound": false
108
+ }
109
+ ```
110
+
111
+ **Allowed Settings:**
112
+
113
+ - `YOLO-min-size` (float): Minimum object size (0.0-1.0)
114
+ - `YOLO-conf-thresh` (float): Confidence threshold (0.0-1.0)
115
+ - `YOLO-max-dets` (int): Maximum detections
116
+ - `YOLO-model-filename` (string): YOLO model file
117
+ - `classifier-model-filename` (string): Classifier model file
118
+ - `sound-path` (string): Path to sound files
119
+ - `deterrent-sound-file` (string): Deterrent sound filename
120
+ - `play-sound` (boolean): Enable/disable sound playback
121
+
122
+ **Response:**
123
+
124
+ ```json
125
+ {
126
+ "success": true,
127
+ "message": "Settings updated"
128
+ }
129
+ ```
130
+
131
+ **Status Codes:**
132
+
133
+ - `200 OK`: Success
134
+ - `400 Bad Request`: Invalid data
135
+
136
+ ---
137
+
138
+ #### POST `/api/settings/save`
139
+
140
+ Save current settings to a YAML file.
141
+
142
+ **Request Body:**
143
+
144
+ ```json
145
+ {
146
+ "filepath": "/path/to/settings.yaml" // Optional, uses default if not provided
147
+ }
148
+ ```
149
+
150
+ **Response:**
151
+
152
+ ```json
153
+ {
154
+ "success": true,
155
+ "filepath": "/home/user/.config/pumaguard/settings.yaml"
156
+ }
157
+ ```
158
+
159
+ **Status Codes:**
160
+
161
+ - `200 OK`: Success
162
+ - `500 Internal Server Error`: Save failed
163
+
164
+ ---
165
+
166
+ #### POST `/api/settings/load`
167
+
168
+ Load settings from a YAML file.
169
+
170
+ **Request Body:**
171
+
172
+ ```json
173
+ {
174
+ "filepath": "/path/to/settings.yaml"
175
+ }
176
+ ```
177
+
178
+ **Response:**
179
+
180
+ ```json
181
+ {
182
+ "success": true,
183
+ "message": "Settings loaded"
184
+ }
185
+ ```
186
+
187
+ **Status Codes:**
188
+
189
+ - `200 OK`: Success
190
+ - `400 Bad Request`: No filepath provided
191
+ - `404 Not Found`: File not found
192
+
193
+ ---
194
+
195
+ ### Directories
196
+
197
+ #### GET `/api/directories`
198
+
199
+ Get list of monitored image directories.
200
+
201
+ **Response:**
202
+
203
+ ```json
204
+ {
205
+ "directories": [
206
+ "/path/to/folder1",
207
+ "/path/to/folder2"
208
+ ]
209
+ }
210
+ ```
211
+
212
+ **Status Codes:**
213
+
214
+ - `200 OK`: Success
215
+
216
+ ---
217
+
218
+ #### POST `/api/directories`
219
+
220
+ Add a directory to the watch list.
221
+
222
+ **Request Body:**
223
+
224
+ ```json
225
+ {
226
+ "directory": "/path/to/new/folder"
227
+ }
228
+ ```
229
+
230
+ **Response:**
231
+
232
+ ```json
233
+ {
234
+ "success": true,
235
+ "directories": [
236
+ "/path/to/folder1",
237
+ "/path/to/folder2",
238
+ "/path/to/new/folder"
239
+ ]
240
+ }
241
+ ```
242
+
243
+ **Status Codes:**
244
+
245
+ - `200 OK`: Success
246
+ - `400 Bad Request`: No directory provided or directory doesn't exist
247
+
248
+ ---
249
+
250
+ #### DELETE `/api/directories/{index}`
251
+
252
+ Remove a directory from the watch list by index.
253
+
254
+ **Path Parameters:**
255
+
256
+ - `index` (integer): Zero-based index of directory to remove
257
+
258
+ **Response:**
259
+
260
+ ```json
261
+ {
262
+ "success": true,
263
+ "directories": [
264
+ "/path/to/folder1"
265
+ ]
266
+ }
267
+ ```
268
+
269
+ **Status Codes:**
270
+
271
+ - `200 OK`: Success
272
+ - `400 Bad Request`: Invalid index
273
+
274
+ ---
275
+
276
+ ### Photos & Images
277
+
278
+ #### GET `/api/photos`
279
+
280
+ Get list of all captured photos across all monitored directories.
281
+
282
+ **Response:**
283
+
284
+ ```json
285
+ {
286
+ "photos": [
287
+ {
288
+ "filename": "image1.jpg",
289
+ "path": "/path/to/folder/image1.jpg",
290
+ "directory": "/path/to/folder",
291
+ "size": 1024000,
292
+ "modified": 1234567890.0,
293
+ "created": 1234567890.0
294
+ }
295
+ ],
296
+ "total": 1
297
+ }
298
+ ```
299
+
300
+ **Notes:**
301
+
302
+ - Photos are sorted by modified time (newest first)
303
+ - Supported formats: .jpg, .jpeg, .png, .gif, .bmp, .webp
304
+
305
+ **Status Codes:**
306
+
307
+ - `200 OK`: Success
308
+
309
+ ---
310
+
311
+ #### GET `/api/photos/{filepath}`
312
+
313
+ Get a specific photo file.
314
+
315
+ **Path Parameters:**
316
+
317
+ - `filepath` (string): URL-encoded full path to the image
318
+
319
+ **Example:**
320
+
321
+ ```
322
+ GET /api/photos/%2Fpath%2Fto%2Fimage.jpg
323
+ ```
324
+
325
+ **Response:**
326
+
327
+ - Binary image data
328
+
329
+ **Status Codes:**
330
+
331
+ - `200 OK`: Success, returns image file
332
+ - `403 Forbidden`: File not in allowed directory
333
+ - `404 Not Found`: File doesn't exist
334
+
335
+ **Security:**
336
+
337
+ - Only files in monitored directories can be accessed
338
+ - Path traversal attempts are blocked
339
+
340
+ ---
341
+
342
+ #### DELETE `/api/photos/{filepath}`
343
+
344
+ Delete a specific photo.
345
+
346
+ **Path Parameters:**
347
+
348
+ - `filepath` (string): URL-encoded full path to the image
349
+
350
+ **Response:**
351
+
352
+ ```json
353
+ {
354
+ "success": true,
355
+ "message": "Photo deleted"
356
+ }
357
+ ```
358
+
359
+ **Status Codes:**
360
+
361
+ - `200 OK`: Success
362
+ - `403 Forbidden`: File not in allowed directory
363
+ - `404 Not Found`: File doesn't exist
364
+
365
+ ---
366
+
367
+ ### Image Browser & Folders
368
+
369
+ #### GET `/api/folders`
370
+
371
+ Get list of watched folders with image counts.
372
+
373
+ **Response:**
374
+
375
+ ```json
376
+ {
377
+ "folders": [
378
+ {
379
+ "path": "/path/to/folder1",
380
+ "name": "folder1",
381
+ "image_count": 42
382
+ },
383
+ {
384
+ "path": "/path/to/folder2",
385
+ "name": "folder2",
386
+ "image_count": 15
387
+ }
388
+ ]
389
+ }
390
+ ```
391
+
392
+ **Status Codes:**
393
+
394
+ - `200 OK`: Success
395
+
396
+ ---
397
+
398
+ #### GET `/api/folders/{folder_path}/images`
399
+
400
+ Get list of images in a specific folder.
401
+
402
+ **Path Parameters:**
403
+
404
+ - `folder_path` (string): URL-encoded folder path
405
+
406
+ **Example:**
407
+
408
+ ```
409
+ GET /api/folders/%2Fpath%2Fto%2Ffolder1/images
410
+ ```
411
+
412
+ **Response:**
413
+
414
+ ```json
415
+ {
416
+ "images": [
417
+ {
418
+ "filename": "IMG_001.jpg",
419
+ "path": "/path/to/folder1/IMG_001.jpg",
420
+ "size": 2048000,
421
+ "modified": 1234567890.0,
422
+ "created": 1234567890.0
423
+ }
424
+ ],
425
+ "folder": "/path/to/folder1"
426
+ }
427
+ ```
428
+
429
+ **Notes:**
430
+
431
+ - Images sorted by modified time (newest first)
432
+ - Only images in allowed directories are returned
433
+
434
+ **Status Codes:**
435
+
436
+ - `200 OK`: Success
437
+ - `403 Forbidden`: Folder not in allowed directories
438
+ - `404 Not Found`: Folder doesn't exist
439
+
440
+ ---
441
+
442
+ ### Smart Sync
443
+
444
+ #### POST `/api/sync/checksums`
445
+
446
+ Compare client-side checksums with server-side files to determine what needs to be downloaded.
447
+
448
+ **Request Body:**
449
+
450
+ ```json
451
+ {
452
+ "files": {
453
+ "/path/to/image1.jpg": "abc123def456...",
454
+ "/path/to/image2.jpg": "789ghi012jkl..."
455
+ }
456
+ }
457
+ ```
458
+
459
+ **Notes:**
460
+
461
+ - Keys are full file paths on server
462
+ - Values are SHA256 checksums (hex string) of local files
463
+ - Empty string for checksum means file doesn't exist locally
464
+
465
+ **Response:**
466
+
467
+ ```json
468
+ {
469
+ "files_to_download": [
470
+ {
471
+ "path": "/path/to/image1.jpg",
472
+ "checksum": "xyz789abc123...",
473
+ "size": 2048000,
474
+ "modified": 1234567890.0
475
+ }
476
+ ],
477
+ "total": 1
478
+ }
479
+ ```
480
+
481
+ **Notes:**
482
+
483
+ - Returns only files that don't match client checksums
484
+ - Files not in allowed directories are silently skipped
485
+
486
+ **Status Codes:**
487
+
488
+ - `200 OK`: Success
489
+ - `400 Bad Request`: No files provided
490
+
491
+ **Use Case:**
492
+ This implements rsync-like functionality where only changed or new files are downloaded.
493
+
494
+ ---
495
+
496
+ #### POST `/api/sync/download`
497
+
498
+ Download one or more files.
499
+
500
+ **Request Body:**
501
+
502
+ ```json
503
+ {
504
+ "files": [
505
+ "/path/to/image1.jpg",
506
+ "/path/to/image2.jpg"
507
+ ]
508
+ }
509
+ ```
510
+
511
+ **Response:**
512
+
513
+ - **Single file**: Binary image data with original filename
514
+ - **Multiple files**: ZIP archive containing all files (filename: `pumaguard_images.zip`)
515
+
516
+ **Headers:**
517
+
518
+ - Single file: `Content-Type: image/jpeg` (or appropriate type)
519
+ - Multiple files: `Content-Type: application/zip`
520
+ - `Content-Disposition: attachment; filename="..."`
521
+
522
+ **Status Codes:**
523
+
524
+ - `200 OK`: Success, returns file(s)
525
+ - `400 Bad Request`: No files provided or no valid files
526
+ - `403 Forbidden`: Files not in allowed directories
527
+
528
+ **Notes:**
529
+
530
+ - Only files in monitored directories can be downloaded
531
+ - Invalid file paths are silently skipped
532
+ - ZIP file contains files with their original filenames
533
+
534
+ ---
535
+
536
+ ## Error Responses
537
+
538
+ All error responses follow this format:
539
+
540
+ ```json
541
+ {
542
+ "error": "Description of what went wrong"
543
+ }
544
+ ```
545
+
546
+ Common HTTP status codes:
547
+
548
+ - `200 OK`: Request succeeded
549
+ - `400 Bad Request`: Invalid request data
550
+ - `403 Forbidden`: Access denied (path not allowed)
551
+ - `404 Not Found`: Resource doesn't exist
552
+ - `500 Internal Server Error`: Server-side error
553
+
554
+ ## Data Types
555
+
556
+ ### Timestamp
557
+
558
+ - Format: Unix timestamp (float)
559
+ - Represents seconds since epoch
560
+ - Example: `1234567890.0` = 2009-02-13 23:31:30 UTC
561
+
562
+ ### File Size
563
+
564
+ - Format: Integer (bytes)
565
+ - Example: `1024000` = 1000 KB
566
+
567
+ ### File Path
568
+
569
+ - Format: Absolute path string
570
+ - Must be in a monitored directory
571
+ - Example: `/home/user/pumaguard/images/photo.jpg`
572
+
573
+ ### Checksum
574
+
575
+ - Format: SHA256 hex string (64 characters)
576
+ - Example: `"abc123def456789..."`
577
+
578
+ ## Security Considerations
579
+
580
+ ### Path Validation
581
+
582
+ All file paths are validated to ensure they are within monitored directories:
583
+
584
+ ```python
585
+ abs_filepath = os.path.abspath(filepath)
586
+ allowed = abs_filepath.startswith(allowed_directory)
587
+ ```
588
+
589
+ ### Path Traversal Prevention
590
+
591
+ - All paths converted to absolute paths
592
+ - Checked against allowed directory list
593
+ - `../` and similar patterns are neutralized
594
+
595
+ ### CORS
596
+
597
+ - Enabled for all origins
598
+ - Required for web UI to work from any IP/hostname
599
+ - All methods (GET, POST, PUT, DELETE, OPTIONS) allowed
600
+
601
+ ## mDNS Service Discovery
602
+
603
+ PumaGuard advertises itself via mDNS (Zeroconf):
604
+
605
+ - Service type: `_pumaguard._tcp.local.`
606
+ - Default port: `5000`
607
+ - Can be disabled with `--no-mdns` flag
608
+
609
+ The Flutter UI can discover PumaGuard servers on the local network using the `multicast_dns` package.
610
+
611
+ ## Image File Types
612
+
613
+ Supported image extensions:
614
+
615
+ - `.jpg`, `.jpeg`
616
+ - `.png`
617
+ - `.gif`
618
+ - `.bmp`
619
+ - `.webp`
620
+
621
+ Files with other extensions are ignored by the API.
622
+
623
+ ## API Usage Examples
624
+
625
+ ### Flutter/Dart
626
+
627
+ ```dart
628
+ // Get status
629
+ final response = await http.get(
630
+ Uri.parse('http://localhost:5000/api/status'),
631
+ headers: {'Content-Type': 'application/json'},
632
+ );
633
+ final data = jsonDecode(response.body);
634
+
635
+ // Update settings
636
+ await http.put(
637
+ Uri.parse('http://localhost:5000/api/settings'),
638
+ headers: {'Content-Type': 'application/json'},
639
+ body: jsonEncode({
640
+ 'YOLO-conf-thresh': 0.30,
641
+ 'play-sound': false,
642
+ }),
643
+ );
644
+
645
+ // Get folders
646
+ final folders = await http.get(
647
+ Uri.parse('http://localhost:5000/api/folders'),
648
+ );
649
+
650
+ // Download files
651
+ final files = ['/path/to/image1.jpg', '/path/to/image2.jpg'];
652
+ final response = await http.post(
653
+ Uri.parse('http://localhost:5000/api/sync/download'),
654
+ headers: {'Content-Type': 'application/json'},
655
+ body: jsonEncode({'files': files}),
656
+ );
657
+ final zipBytes = response.bodyBytes;
658
+ ```
659
+
660
+ ### cURL
661
+
662
+ ```bash
663
+ # Get status
664
+ curl http://localhost:5000/api/status
665
+
666
+ # Update settings
667
+ curl -X PUT http://localhost:5000/api/settings \
668
+ -H "Content-Type: application/json" \
669
+ -d '{"YOLO-conf-thresh": 0.30}'
670
+
671
+ # Get folders
672
+ curl http://localhost:5000/api/folders
673
+
674
+ # Download image
675
+ curl http://localhost:5000/api/photos/%2Fpath%2Fto%2Fimage.jpg -o image.jpg
676
+
677
+ # Download multiple as ZIP
678
+ curl -X POST http://localhost:5000/api/sync/download \
679
+ -H "Content-Type: application/json" \
680
+ -d '{"files": ["/path/to/image1.jpg", "/path/to/image2.jpg"]}' \
681
+ -o images.zip
682
+ ```
683
+
684
+ ## Rate Limiting
685
+
686
+ Currently, there is no rate limiting implemented. Consider implementing rate limiting if exposing the API to untrusted networks.
687
+
688
+ ## Future API Extensions
689
+
690
+ Planned but not yet implemented:
691
+
692
+ - Authentication and authorization
693
+ - WebSocket support for real-time updates
694
+ - Pagination for large image lists
695
+ - Image thumbnail generation
696
+ - Batch operations (delete multiple files)
697
+ - Search and filter endpoints
698
+ - Classification result history
699
+
700
+ ## Changelog
701
+
702
+ ### Version 1.0
703
+
704
+ - Initial API implementation
705
+ - Settings management
706
+ - Directory monitoring
707
+ - Photo listing and access
708
+ - Image browser with folders
709
+ - Smart sync with checksums
710
+ - File download (single and ZIP)
711
+
712
+ ## Support
713
+
714
+ For API issues or questions:
715
+
716
+ - GitHub: <https://github.com/PEEC-Nature-Youth-Group/pumaguard>
717
+ - Documentation: <http://pumaguard.rtfd.io/>