pumaguard 21.post29__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.
- pumaguard/presets.py +1 -0
- pumaguard/pumaguard-ui/.last_build_id +1 -1
- pumaguard/pumaguard-ui/assets/NOTICES +621 -71
- pumaguard/pumaguard-ui/assets/fonts/MaterialIcons-Regular.otf +0 -0
- pumaguard/pumaguard-ui/flutter_bootstrap.js +1 -1
- pumaguard/pumaguard-ui/main.dart.js +28869 -28787
- pumaguard/web_routes/dhcp.py +311 -54
- pumaguard/web_routes/diagnostics.py +6 -0
- pumaguard/web_routes/settings.py +13 -0
- pumaguard/web_ui.py +29 -0
- {pumaguard-21.post29.dist-info → pumaguard-21.post83.dist-info}/METADATA +1 -1
- pumaguard-21.post83.dist-info/RECORD +254 -0
- pumaguard-ui/.gitignore +48 -0
- pumaguard-ui/.metadata +45 -0
- pumaguard-ui/API_REFERENCE.md +717 -0
- pumaguard-ui/LICENSE +201 -0
- pumaguard-ui/Makefile +36 -0
- pumaguard-ui/README.md +371 -0
- pumaguard-ui/UI_DEVELOPMENT_CONTEXT.md +427 -0
- pumaguard-ui/analysis_options.yaml +28 -0
- pumaguard-ui/android/.gitignore +14 -0
- pumaguard-ui/android/app/build.gradle.kts +44 -0
- pumaguard-ui/android/app/src/debug/AndroidManifest.xml +7 -0
- pumaguard-ui/android/app/src/main/AndroidManifest.xml +45 -0
- pumaguard-ui/android/app/src/main/kotlin/com/example/pumaguard_ui/MainActivity.kt +5 -0
- pumaguard-ui/android/app/src/main/res/drawable/launch_background.xml +12 -0
- pumaguard-ui/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
- pumaguard-ui/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- pumaguard-ui/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- pumaguard-ui/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- pumaguard-ui/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- pumaguard-ui/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- pumaguard-ui/android/app/src/main/res/values/styles.xml +18 -0
- pumaguard-ui/android/app/src/main/res/values-night/styles.xml +18 -0
- pumaguard-ui/android/app/src/profile/AndroidManifest.xml +7 -0
- pumaguard-ui/android/build.gradle.kts +24 -0
- pumaguard-ui/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- pumaguard-ui/android/gradle.properties +2 -0
- pumaguard-ui/android/settings.gradle.kts +26 -0
- pumaguard-ui/fonts/README.md +38 -0
- pumaguard-ui/fonts/Roboto-Bold.ttf +0 -0
- pumaguard-ui/fonts/Roboto-Light.ttf +0 -0
- pumaguard-ui/fonts/Roboto-Medium.ttf +0 -0
- pumaguard-ui/fonts/Roboto-Regular.ttf +0 -0
- pumaguard-ui/fonts/RobotoMono-Bold.ttf +0 -0
- pumaguard-ui/fonts/RobotoMono-Medium.ttf +0 -0
- pumaguard-ui/fonts/RobotoMono-Regular.ttf +0 -0
- pumaguard-ui/fonts/download_fonts.sh +76 -0
- pumaguard-ui/ios/.gitignore +34 -0
- pumaguard-ui/ios/Flutter/AppFrameworkInfo.plist +26 -0
- pumaguard-ui/ios/Flutter/Debug.xcconfig +1 -0
- pumaguard-ui/ios/Flutter/Release.xcconfig +1 -0
- pumaguard-ui/ios/Runner/AppDelegate.swift +13 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +122 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +23 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png +0 -0
- pumaguard-ui/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +5 -0
- pumaguard-ui/ios/Runner/Base.lproj/LaunchScreen.storyboard +37 -0
- pumaguard-ui/ios/Runner/Base.lproj/Main.storyboard +26 -0
- pumaguard-ui/ios/Runner/Info.plist +49 -0
- pumaguard-ui/ios/Runner/Runner-Bridging-Header.h +1 -0
- pumaguard-ui/ios/Runner.xcodeproj/project.pbxproj +616 -0
- pumaguard-ui/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- pumaguard-ui/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- pumaguard-ui/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- pumaguard-ui/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +101 -0
- pumaguard-ui/ios/Runner.xcworkspace/contents.xcworkspacedata +7 -0
- pumaguard-ui/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- pumaguard-ui/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- pumaguard-ui/ios/RunnerTests/RunnerTests.swift +12 -0
- pumaguard-ui/lib/main.dart +56 -0
- pumaguard-ui/lib/models/camera.dart +45 -0
- pumaguard-ui/lib/models/plug.dart +45 -0
- pumaguard-ui/lib/models/settings.dart +112 -0
- pumaguard-ui/lib/models/status.dart +58 -0
- pumaguard-ui/lib/screens/directories_screen.dart +319 -0
- pumaguard-ui/lib/screens/home_screen.dart +545 -0
- pumaguard-ui/lib/screens/image_browser_screen.dart +1248 -0
- pumaguard-ui/lib/screens/server_discovery_screen.dart +390 -0
- pumaguard-ui/lib/screens/settings_screen.dart +1162 -0
- pumaguard-ui/lib/screens/wifi_settings_screen.dart +671 -0
- pumaguard-ui/lib/services/api_service.dart +717 -0
- pumaguard-ui/lib/services/camera_events_service.dart +195 -0
- pumaguard-ui/lib/services/mdns_service.dart +4 -0
- pumaguard-ui/lib/services/mdns_service_impl.dart +282 -0
- pumaguard-ui/lib/services/mdns_service_io.dart +1 -0
- pumaguard-ui/lib/services/mdns_service_web.dart +106 -0
- pumaguard-ui/lib/utils/download_helper.dart +2 -0
- pumaguard-ui/lib/utils/download_helper_stub.dart +6 -0
- pumaguard-ui/lib/utils/download_helper_web.dart +14 -0
- pumaguard-ui/lib/utils/platform_url.dart +10 -0
- pumaguard-ui/lib/utils/platform_url_stub.dart +11 -0
- pumaguard-ui/lib/utils/platform_url_web.dart +16 -0
- pumaguard-ui/linux/.gitignore +1 -0
- pumaguard-ui/linux/CMakeLists.txt +128 -0
- pumaguard-ui/linux/flutter/CMakeLists.txt +88 -0
- pumaguard-ui/linux/flutter/generated_plugin_registrant.cc +15 -0
- pumaguard-ui/linux/flutter/generated_plugin_registrant.h +15 -0
- pumaguard-ui/linux/flutter/generated_plugins.cmake +24 -0
- pumaguard-ui/linux/runner/CMakeLists.txt +26 -0
- pumaguard-ui/linux/runner/main.cc +6 -0
- pumaguard-ui/linux/runner/my_application.cc +148 -0
- pumaguard-ui/linux/runner/my_application.h +21 -0
- pumaguard-ui/macos/.gitignore +7 -0
- pumaguard-ui/macos/Flutter/Flutter-Debug.xcconfig +1 -0
- pumaguard-ui/macos/Flutter/Flutter-Release.xcconfig +1 -0
- pumaguard-ui/macos/Flutter/GeneratedPluginRegistrant.swift +16 -0
- pumaguard-ui/macos/Runner/AppDelegate.swift +13 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
- pumaguard-ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
- pumaguard-ui/macos/Runner/Base.lproj/MainMenu.xib +343 -0
- pumaguard-ui/macos/Runner/Configs/AppInfo.xcconfig +14 -0
- pumaguard-ui/macos/Runner/Configs/Debug.xcconfig +2 -0
- pumaguard-ui/macos/Runner/Configs/Release.xcconfig +2 -0
- pumaguard-ui/macos/Runner/Configs/Warnings.xcconfig +13 -0
- pumaguard-ui/macos/Runner/DebugProfile.entitlements +12 -0
- pumaguard-ui/macos/Runner/Info.plist +32 -0
- pumaguard-ui/macos/Runner/MainFlutterWindow.swift +15 -0
- pumaguard-ui/macos/Runner/Release.entitlements +8 -0
- pumaguard-ui/macos/Runner.xcodeproj/project.pbxproj +705 -0
- pumaguard-ui/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- pumaguard-ui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +99 -0
- pumaguard-ui/macos/Runner.xcworkspace/contents.xcworkspacedata +7 -0
- pumaguard-ui/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- pumaguard-ui/macos/RunnerTests/RunnerTests.swift +12 -0
- pumaguard-ui/pubspec.lock +882 -0
- pumaguard-ui/pubspec.yaml +125 -0
- pumaguard-ui/test/models/camera_test.dart +515 -0
- pumaguard-ui/test/models/plug_test.dart +499 -0
- pumaguard-ui/test/models/settings_test.dart +903 -0
- pumaguard-ui/test/models/status_test.dart +707 -0
- pumaguard-ui/test/screens/image_browser_grouping_test.dart +555 -0
- pumaguard-ui/test/services/api_service_cameras_test.dart +580 -0
- pumaguard-ui/test/services/api_service_image_browser_test.dart +512 -0
- pumaguard-ui/test/widget_test.dart.skip +38 -0
- pumaguard-ui/web/favicon.png +0 -0
- pumaguard-ui/web/icons/Icon-192.png +0 -0
- pumaguard-ui/web/icons/Icon-512.png +0 -0
- pumaguard-ui/web/icons/Icon-maskable-192.png +0 -0
- pumaguard-ui/web/icons/Icon-maskable-512.png +0 -0
- pumaguard-ui/web/index.html +38 -0
- pumaguard-ui/web/manifest.json +35 -0
- pumaguard-ui/windows/.gitignore +17 -0
- pumaguard-ui/windows/CMakeLists.txt +108 -0
- pumaguard-ui/windows/flutter/CMakeLists.txt +109 -0
- pumaguard-ui/windows/flutter/generated_plugin_registrant.cc +14 -0
- pumaguard-ui/windows/flutter/generated_plugin_registrant.h +15 -0
- pumaguard-ui/windows/flutter/generated_plugins.cmake +24 -0
- pumaguard-ui/windows/runner/CMakeLists.txt +40 -0
- pumaguard-ui/windows/runner/Runner.rc +121 -0
- pumaguard-ui/windows/runner/flutter_window.cpp +71 -0
- pumaguard-ui/windows/runner/flutter_window.h +33 -0
- pumaguard-ui/windows/runner/main.cpp +43 -0
- pumaguard-ui/windows/runner/resource.h +16 -0
- pumaguard-ui/windows/runner/resources/app_icon.ico +0 -0
- pumaguard-ui/windows/runner/runner.exe.manifest +14 -0
- pumaguard-ui/windows/runner/utils.cpp +65 -0
- pumaguard-ui/windows/runner/utils.h +19 -0
- pumaguard-ui/windows/runner/win32_window.cpp +288 -0
- pumaguard-ui/windows/runner/win32_window.h +102 -0
- pumaguard-21.post29.dist-info/RECORD +0 -83
- {pumaguard-21.post29.dist-info → pumaguard-21.post83.dist-info}/WHEEL +0 -0
- {pumaguard-21.post29.dist-info → pumaguard-21.post83.dist-info}/entry_points.txt +0 -0
- {pumaguard-21.post29.dist-info → pumaguard-21.post83.dist-info}/licenses/LICENSE +0 -0
- {pumaguard-21.post29.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/>
|