135 Commits

Author SHA1 Message Date
eduard256 671da40930 Add Umbrel install section to README 2026-04-24 11:26:13 +00:00
eduard256 e0158ea81a Add Podman section to README with required capabilities 2026-04-24 11:26:13 +00:00
eduard256 593f2fc14f Sync README install command 2026-04-16 19:00:45 +00:00
eduard256 0a41dac8e4 Sync install.sh fix 2026-04-16 18:58:46 +00:00
eduard256 1f8414079a Replace install.sh with new modular navigator 2026-04-16 18:57:35 +00:00
eduard256 43a097586a Sync scripts from develop 2026-04-16 18:54:08 +00:00
eduard256 fb4797f6b3 Sync scripts from develop 2026-04-16 18:47:55 +00:00
eduard256 4308039e08 Sync scripts from develop 2026-04-16 18:00:56 +00:00
eduard256 df32774b50 Remove test script 2026-04-16 17:51:33 +00:00
eduard256 100149241c Sync all scripts to main 2026-04-16 17:51:19 +00:00
eduard256 f6c80a2c72 Update install.sh with system detection display 2026-04-16 17:06:23 +00:00
eduard256 c86f1b936e Add modular installer scripts
Worker scripts with JSON event streaming:
- detect.sh: system/Docker/Frigate/go2rtc detection
- prepare.sh: Docker and Compose installation
- strix.sh: deploy Strix standalone
- strix-frigate.sh: deploy Strix + Frigate with HW autodetect
- proxmox-lxc-create.sh: create Ubuntu LXC on Proxmox
- install.sh: animated frontend with owl display
2026-04-16 16:56:17 +00:00
eduard256 ffe77cb9c4 Merge develop into main for v2.1.0 release 2026-04-08 11:31:03 +00:00
eduard256 29e03ce85a Release v2.1.0 2026-04-08 11:30:58 +00:00
eduard256 e47c0f7ce6 Add top-1000 checkbox to ONVIF page, classify JPEG streams as alternative
- Add checked-by-default checkbox to also test popular stream patterns
- Move JPEG-only streams (no H264/H265) to Alternative group in test results
2026-04-08 11:27:08 +00:00
eduard256 0fb7356a5e Add ONVIF stream handler for tester
- Add testOnvif(): resolves all profiles via ONVIF client, tests
  each RTSP stream, returns two Results per profile (onvif + rtsp)
  with shared screenshot
- Route onvif:// URLs in worker.go alongside homekit://
- Classify onvif:// streams as recommended in test.html
- Harden create.html against undefined/null URL values
2026-04-08 11:00:32 +00:00
eduard256 ce4b777e98 Add ONVIF camera page and probe routing
- Add onvif.html: credentials form, Discover Streams button,
  fallback to Standard Discovery and HomeKit Pairing
- Update index.html routing: onvif type -> onvif.html with all
  probe params (onvif_url, onvif_port, onvif_name, onvif_hardware,
  mdns_* for HomeKit fallback)
2026-04-08 10:50:05 +00:00
eduard256 5be8d4aa00 Add ONVIF probe detector via unicast WS-Discovery
- Add ProbeONVIF() prober: sends unicast WS-Discovery to ip:3702,
  parses XAddrs, Name, Hardware from response (no auth needed)
- Add ONVIFResult struct to probe models
- Register ONVIF detector with highest priority (before HomeKit)
- Fix homekit.html back-wrapper max-width to match design system
2026-04-08 10:31:46 +00:00
eduard256 1291e6a5b6 Add frontend_design_strix skill for UI page creation
Design guide with principles, layout patterns, component usage,
navigation rules, and checklist. References homekit.html as the
design gold standard and design-system.html for components.
2026-04-08 09:49:25 +00:00
eduard256 699ddda39b Update design system with centered layout, PIN input, floating back button
Add true-center layout pattern, back-wrapper for floating navigation,
PIN digit input component with all states, and centered page demo
with HomeKit logo example. Document PIN input JS pattern.
2026-04-08 09:39:36 +00:00
eduard256 89c5d83a6f Refine HomeKit page: add Apple HomeKit logo, centered layout, back button
Replace text-only header with official HomeKit house icon and
"Apple HomeKit" label. Pin input centered on screen, back button
aligned to container edge. Remove device info table and decorative
elements for a cleaner look matching the rest of the frontend.
2026-04-08 09:30:31 +00:00
eduard256 8398832960 Redesign HomeKit page, add design system reference
Rebuild homekit.html with centered layout, cleaner PIN input,
and consistent styling matching the rest of the frontend.
Add www/design-system.html as a living component reference
for all UI elements used across the Strix frontend.
2026-04-08 08:54:40 +00:00
eduard256 a16799fa8d Add Docker Compose files for Strix, Frigate, and go2rtc setups
Add three docker-compose variants: standalone Strix,
Strix + Frigate, and Strix + go2rtc. Update README with
Docker Compose install instructions linking to the files.
2026-04-05 14:47:54 +00:00
eduard256 0652e53bc7 Update README: add HomeKit protocol and StrixAHKCamFake reference 2026-04-05 14:41:19 +00:00
eduard256 528ec8e00b Add HomeKit stream testing via HAP snapshot
- Add worker_homekit.go with direct hap.Dial + GetImage flow
- Bypass SRTP/Producer pipeline for homekit:// URLs
- Route homekit:// streams to dedicated handler in worker.go
2026-04-05 12:58:26 +00:00
eduard256 a9820abc37 Add HomeKit camera pairing support
- Add POST /api/homekit/pair endpoint that calls hap.Pair() from go2rtc
- Rewrite homekit.html with PIN input UI (XXX-XX-XXX format)
- Auto-advance between digit fields, paste support, error/success states
- On successful pairing, redirect to create.html with homekit:// URL
- Pass mdns_port and mdns_paired from probe to homekit.html
- Detect HomeKit cameras regardless of pairing status
2026-04-05 12:43:06 +00:00
eduard256 e2e24c7578 Switch mDNS probe to multicast, use mDNS for reachability
Unicast mDNS queries (direct to IP:5353) are ignored by some HomeKit
devices. Switch to multicast (224.0.0.251:5353) and filter responses
by sender IP. Also consider mDNS response as reachability signal.

Split probe timeouts: 100ms for ports/DNS/HTTP, 120ms total to give
mDNS extra time. HomeKit responds in ~0.2ms via multicast.
2026-04-05 12:06:11 +00:00
eduard256 f084135701 Remove ICMP ping from probe, add HomeKit port 51826
ICMP requires root or CAP_NET_RAW which is not available in
unprivileged containers. Probe now relies solely on port scanning
for reachability detection, which works without any special
permissions. Add port 51826 (HomeKit) to both default and
database-loaded port lists.
2026-04-05 11:54:24 +00:00
eduard256 4e9ffd1440 Show LAN IP instead of localhost in install summary
Detect local network IP address using ip route / hostname -I / ifconfig
fallback chain and display it in the post-install summary box so users
can immediately open Strix from other devices on the network.
2026-04-05 10:45:46 +00:00
eduard256 83659c9a82 Replace double dashes with single dashes 2026-04-05 10:36:48 +00:00
eduard256 e0ccef8683 Replace double dashes with single dashes 2026-04-05 10:36:47 +00:00
eduard256 166feceab9 Add StrixCamFake link to DEVELOPERS.md 2026-04-05 10:36:11 +00:00
eduard256 66f9131cff Add StrixCamFake link to DEVELOPERS.md 2026-04-05 10:36:10 +00:00
eduard256 8cf3195b51 Add StrixCamFake link to README 2026-04-05 10:35:51 +00:00
eduard256 600141d11b Add StrixCamFake link to README 2026-04-05 10:35:50 +00:00
eduard256 608d4989ff Link feature bullets to corresponding screenshots 2026-04-05 10:28:55 +00:00
eduard256 5fb1efe599 Link feature bullets to corresponding screenshots 2026-04-05 10:28:54 +00:00
eduard256 2ab8106b01 Add supported cameras link to quick links 2026-04-05 10:25:42 +00:00
eduard256 acc456f3f5 Add supported cameras link to quick links 2026-04-05 10:25:41 +00:00
eduard256 22baefd57f Add camera database browse and contribute links 2026-04-05 10:23:33 +00:00
eduard256 f06d60f6ff Add camera database browse and contribute links 2026-04-05 10:23:32 +00:00
eduard256 6044df6ee4 Add horizontal rule before demo GIF 2026-04-05 10:20:39 +00:00
eduard256 56c02f6b72 Add horizontal rule before demo GIF 2026-04-05 10:20:38 +00:00
eduard256 43632fb8c2 Add live demo, video, and API docs links after banner 2026-04-05 10:19:33 +00:00
eduard256 55a4a62752 Add live demo, video, and API docs links after banner 2026-04-05 10:19:32 +00:00
eduard256 4c1fab86b1 Add separator between logo and title 2026-04-05 10:18:26 +00:00
eduard256 1c50564548 Add separator between logo and title 2026-04-05 10:18:25 +00:00
eduard256 1efe3cc9ba Add STRIX text next to logo in header 2026-04-05 10:17:40 +00:00
eduard256 21c96d6548 Add STRIX text next to logo in header 2026-04-05 10:17:39 +00:00
eduard256 4ea3485c9b Move API reference to DEVELOPERS.md 2026-04-05 10:15:47 +00:00
eduard256 dd8966a8d7 Move API reference to DEVELOPERS.md 2026-04-05 10:15:46 +00:00
eduard256 74eed5ede9 Redesign README header with centered layout and feature list 2026-04-05 10:09:26 +00:00
eduard256 96354f018f Redesign README header with centered layout and feature list 2026-04-05 10:09:25 +00:00
eduard256 75947be26b Remove title text from README header 2026-04-05 10:03:45 +00:00
eduard256 e4a28fe61a Remove title text from README header 2026-04-05 10:03:44 +00:00
eduard256 4cb00ec85f Left-align logo and badges in README 2026-04-05 10:03:15 +00:00
eduard256 2fc9be2d9f Left-align logo and badges in README 2026-04-05 10:03:14 +00:00
eduard256 0cf9f7d44e Remove logo caption from README 2026-04-05 10:02:39 +00:00
eduard256 39da8d2d50 Remove logo caption from README 2026-04-05 10:02:38 +00:00
eduard256 8c1a6b1b0e Add MIT license and license badge 2026-04-05 10:02:03 +00:00
eduard256 258f3712c2 Add MIT license and license badge 2026-04-05 10:02:02 +00:00
eduard256 2db7ae6f25 Move badges above icon in README 2026-04-05 10:00:31 +00:00
eduard256 bb740a04bc Move badges above icon in README 2026-04-05 10:00:30 +00:00
eduard256 09bd2ce220 Use PNG icon in README 2026-04-05 09:00:15 +00:00
eduard256 8a4201936a Use PNG icon in README 2026-04-05 09:00:10 +00:00
eduard256 0a30496991 Add README for v2.0.0 2026-04-05 08:58:55 +00:00
eduard256 eb6719237d Add README for v2.0.0 2026-04-05 08:58:23 +00:00
eduard256 ded8aebcad Merge develop into main for v2.0.0 release
# Conflicts:
#	DOCKER.md
#	README.md
2026-04-05 08:32:14 +00:00
eduard256 e2f84ec0f6 Release v2.0.0 2026-04-05 08:32:05 +00:00
eduard256 5f21a91ff9 Add universal Linux installer script
Bash installer that works on any Linux distro:
- Auto-detects OS and architecture
- Installs Docker via get.docker.com if missing
- Installs Docker Compose plugin if missing
- Auto-discovers local Frigate and go2rtc instances
- Interactive dialogs with 10s timeouts
- Generates docker-compose.yml and .env in /opt/strix/
- Supports install and update modes
- CLI flags for non-interactive use (--yes, --version, --no-logo)
- Returns machine-readable status for parent scripts (Proxmox LXC)
2026-04-05 08:13:28 +00:00
eduard256 44ab0651cb Add DVRIP protocol support
- Register dvrip stream handler using go2rtc pkg/dvrip
- Add default port 34567 for dvrip scheme in URL builder
2026-04-03 21:01:39 +00:00
eduard256 51b11e233f Add RTMP protocol support
Register rtmp, rtmps, rtmpx stream handlers using go2rtc
pkg/rtmp.DialPlay for TCP connect, handshake, and play.
2026-04-03 20:33:30 +00:00
eduard256 d59816543d Add direct stream URL input support to web UI 2026-04-03 20:03:45 +00:00
eduard256 4880e1ad14 Add 15s timeout for HTTP handler requests
Cameras under load may accept TCP connection but never respond,
hanging tester workers indefinitely. Context timeout on the HTTP
request ensures workers are released.
2026-04-03 19:26:17 +00:00
eduard256 6abb8409cb Add HTTP/HTTPS protocol support for snapshots and streams
Register http, https, httpx handlers with content-type detection:
- image/jpeg: single JPEG snapshots via go2rtc image.Open
- multipart/x-mixed-replace: MJPEG streams via mpjpeg.Open
- application/vnd.apple.mpegurl: HLS via hls.OpenURL
- auto-detect fallback via magic.Open (MPEG-TS, raw MJPEG, etc.)

Uses go2rtc tcp.Do for Basic + Digest auth and TLS handling.
2026-04-03 16:03:45 +00:00
eduard256 8ce89bec75 Always include port in URL for protocols with raw TCP dial
Bubble protocol uses net.DialTimeout with u.Host directly,
which requires explicit port. Add portRequired set to force
port in generated URLs for such protocols.
2026-04-01 17:53:00 +00:00
eduard256 8e8f568251 Add bubble protocol support
- Register bubble stream handler using go2rtc pkg/bubble
- Add default port 80 for bubble scheme
2026-04-01 17:24:02 +00:00
eduard256 20d5ad2f0b Fix screenshot URL path: remove leading slash 2026-04-01 16:07:22 +00:00
eduard256 f34a7b96c7 Add go2rtc module, test/config/urls pages, Frigate config fixes 2026-03-26 22:45:32 +00:00
eduard256 8dc8ba1096 Add resolution extraction from JPEG screenshots in tester 2026-03-26 10:40:41 +00:00
eduard256 74b4b61198 Add frontend pages, move static to www/, add resolution to tester
Frontend:
- index.html: probe device, navigate to standard/homekit by type
- standard.html: camera config, model search with multi-select
- create.html: stream URL list, custom URL input, create test session
- homekit.html: HomeKit device info, contact links, fallback to standard

Backend:
- Move static files to www/ package with embed (go2rtc pattern)
- Add initStatic() in api with FileServer
- Add width/height to test results from H264 SPS parsing
- Contribute links to gostrix.github.io with auto-filled params
2026-03-26 10:18:40 +00:00
eduard256 0ecf1eb75f Use app.Env for consistent env var access in frigate module 2026-03-25 19:41:25 +00:00
eduard256 e2fdf0d3d6 Add Frigate config proxy with auto-discovery 2026-03-25 19:20:07 +00:00
eduard256 fe4a5dfa2e Simplify Frigate detection, use known HA addon hostname 2026-03-25 19:08:23 +00:00
eduard256 5fdeca8701 Add raw Supervisor API response to frigate check endpoint 2026-03-25 18:58:53 +00:00
eduard256 124007ea31 Rebuild dev image 2026-03-25 18:46:56 +00:00
eduard256 62dcd89fc5 Simplify listHAAddons to return raw Supervisor API JSON 2026-03-25 18:37:53 +00:00
eduard256 a9ab7e2ba6 Add Frigate autodiscovery via HA Supervisor API 2026-03-25 18:30:38 +00:00
eduard256 b060a5372e Add frigate connectivity check endpoint 2026-03-25 18:15:31 +00:00
eduard256 0bf2a83e9d Add probe detector skill 2026-03-25 17:42:22 +00:00
eduard256 bfeae738e3 Add add_protocol skill, update release skills with DB download step 2026-03-25 17:37:20 +00:00
eduard256 4d171f69c7 Add Dockerfile, fix SQLite immutable mode, URL-encode credentials
- Dockerfile: multi-stage build with golang:1.26 and alpine + ffmpeg
- SQLite: use file: URI with immutable=1 for read-only access
- URL builder: encode user/pass with PathEscape/QueryEscape for
  special characters (@, \, :, etc.)
- Health endpoint: truncate uptime to seconds
- Release skill: update smoke test to /api endpoint
- Remove unused ValidateID function
2026-03-25 11:28:47 +00:00
eduard256 27117900eb Rewrite Strix from scratch as single binary
Complete architecture rewrite following go2rtc patterns:
- pkg/ for pure logic (camdb, tester, probe, generate)
- internal/ for application glue with Init() modules
- Single HTTP server on :4567 with all endpoints
- zerolog with password masking and memory ring buffer
- Environment-based config only (no YAML files)

API endpoints: /api/search, /api/streams, /api/test,
/api/probe, /api/generate, /api/health, /api/log

Dependencies: go2rtc v1.9.14, go-sqlite3, miekg/dns, zerolog
2026-03-25 10:38:46 +00:00
eduard256 51b0d06062 Fix database link to homepage 2026-03-23 20:25:03 +00:00
eduard256 3b29188924 Fix database link to homepage 2026-03-23 20:25:02 +00:00
eduard256 efd04367cf Add camera database browse link to README 2026-03-23 20:21:00 +00:00
eduard256 3a18390f42 Add camera database browse link to README 2026-03-23 20:20:59 +00:00
eduard256 cbe1a428b2 Add camera contribution link to README 2026-03-23 20:17:03 +00:00
eduard256 87c96970a6 Add camera contribution link to README 2026-03-23 20:12:13 +00:00
eduard256 7cab640bf2 Add Podman installation docs with required capabilities
Document NET_RAW and NET_ADMIN capabilities needed for network
scanning when running Strix with Podman. Includes podman run,
podman-compose, and Quadlet (systemd) setup instructions.

Addresses #6
2026-03-22 17:57:24 +00:00
eduard256 9e493a2bac Add Podman installation docs with required capabilities
Document NET_RAW and NET_ADMIN capabilities needed for network
scanning when running Strix with Podman. Includes podman run,
podman-compose, and Quadlet (systemd) setup instructions.

Addresses #6
2026-03-22 17:56:10 +00:00
eduard256 3fafdbc6ce Separate structured logs from human-readable output
Move SetupLogger() to a standalone function called before config.Load()
so the logger is available from the very start. Replace all fmt.Printf
calls in config.go with slog calls. Redirect banner and endpoint info
to stderr, keeping stdout clean for structured log output (JSON/text).

Fixes #5
2026-03-22 17:44:16 +00:00
eduard256 4fe5ae9447 URL-encode credentials with special characters in stream URLs
Passwords containing @, #, :, ?, /, %, &, space and other special
characters broke URL parsing, causing streams to not be detected.

Replaced fmt.Sprintf string concatenation with url.URL struct for
building RTSP/HTTP URLs. Credentials in userinfo are now handled via
url.UserPassword() which encodes special chars automatically.

Split replacePlaceholders into two phases:
- Phase 1: safe placeholders (channel, width, IP, port)
- Phase 2: credential placeholders with context-aware encoding:
  - Query string: url.Values.Set + Encode (auto percent-encoding)
  - Path segments: url.PathEscape

Normal passwords (letters, digits, -._~) produce identical URLs
as before -- encoding is a no-op for safe characters.

Fixes #10
2026-03-22 17:13:38 +00:00
eduard256 3acc966658 Mask URL-encoded passwords in debug logs
SecretStore.Add now registers both plain text and URL-encoded forms
of the password. Fixes cases where passwords with special characters
(e.g. @, #, :) appear percent-encoded in URLs but were not matched
by the masking handler.
2026-03-20 19:59:22 +00:00
eduard256 8cf05a1576 Fix credentials leaking in debug logs (#4)
Add a secret-masking slog.Handler that automatically replaces registered
passwords with "***" in all log output. Secrets are registered per-scan
when a discovery request arrives and unregistered when it completes.

This approach masks credentials everywhere they appear in logs — URL
userinfo, query parameters, path segments, and Go HTTP error messages —
without modifying any business logic in scanner, builder, tester, or
ONVIF components. API responses are unaffected and still return full
URLs with credentials for frontend use.
2026-03-20 11:03:01 +00:00
eduard256 c95740137d Merge icon variants from develop 2026-03-19 12:56:31 +00:00
eduard256 e269e243da Add icon variants with dark background and transparent versions 2026-03-19 12:44:20 +00:00
eduard256 0205e32257 Merge develop into main for v1.0.11 release 2026-03-19 11:33:03 +00:00
eduard256 c576b09e8b Release v1.0.11 2026-03-19 11:32:58 +00:00
eduard256 25f1907fc3 Register HEAD route for health endpoint in chi router 2026-03-19 11:25:57 +00:00
eduard256 cc8c3e4f14 Fix health endpoint HEAD method support, add icon assets
- Allow HEAD requests on /api/v1/health for Docker/CasaOS healthcheck
  compatibility (wget --spider sends HEAD)
- Add project icon in SVG, 192x192 PNG and 512x512 PNG formats
2026-03-19 11:17:22 +00:00
eduard256 4bd2de78dc Merge develop into main for v1.0.10 release 2026-03-17 07:27:07 +00:00
eduard256 89a7c87462 Release v1.0.10 2026-03-17 07:26:58 +00:00
eduard256 e40dccbb90 Remove CI/CD, unify Docker image for Docker Hub and HA add-on
- Remove GitHub Actions workflows (ci.yml, docker.yml, release.yml)
- Remove GoReleaser configuration
- Remove RELEASE.md (replaced by /release_strix skill)
- Add HA options.json support in config.go (reads /data/options.json)
- Add Version field to Config, pass real version to health endpoint
- Change Version from const to var, inject via ldflags at build time
- Add ARG VERSION to Dockerfile for build-time version injection
- Reset webui/package.json version to 0.0.0 (not used functionally)
- Clear probe fields on back navigation in frontend
- Add /release_strix and /release_strix_dev skills
2026-03-17 07:23:04 +00:00
eduard256 fe93aa329c Integrate probe endpoint into frontend
- Add ProbeAPI client (js/api/probe.js)
- Add reusable modal component (js/ui/modal.js) with overlay, animations
- Call GET /api/v1/probe after Check Address click
- Auto-fill Camera Model with vendor from ARP/OUI lookup
- Show modal on unreachable device with Change IP / Continue Anyway buttons
- Add modal CSS styles matching existing dark theme
2026-03-16 20:05:00 +00:00
eduard256 ddf2b4a373 Remove experimental SSE warning from Home Assistant Add-on section 2026-03-16 14:56:55 +00:00
eduard256 833da5cf48 Remove experimental SSE warning from Home Assistant Add-on section 2026-03-16 14:55:57 +00:00
eduard256 3fec89be7f Add HTTP prober, optimize mDNS timeout, add Trassir/ZOSI to OUI
- Add HTTPProber: parallel HEAD+GET on ports 80/8080, extracts Server header
- Reduce mDNS timeout from 1s to 100ms using context wrapper around
  mdns.Query (HomeKit devices respond in 2-10ms, no need to wait 1s)
- Add Trassir (F0:23:B9) and ZOSI (00:05:FE) to camera OUI database
- Probe response time improved from ~1s to ~110ms for reachable devices
2026-03-16 14:46:58 +00:00
eduard256 4d6c2fd878 Add GET /api/v1/probe endpoint for device inspection
Fast (~1-3s) endpoint that gathers network info about a device
before full stream discovery. Runs ping first, then parallel probes.

Features:
- Ping with ICMP + TCP fallback (works without root)
- Reverse DNS hostname lookup
- ARP table MAC address + OUI vendor identification (2403 entries, 51 camera vendors)
- mDNS HomeKit detection (camera/doorbell, paired status)
- Extensible Prober interface for adding new probe types
- 3-second overall timeout, parallel execution

Response includes "type" field:
- "unreachable" - device not responding
- "standard" - normal IP camera (RTSP/HTTP/ONVIF flow)
- "homekit" - Apple HomeKit camera (PIN pairing flow)
2026-03-16 13:57:41 +00:00
eduard256 eb8cc546c8 Merge main into develop: Add release documentation 2025-12-11 16:53:02 +00:00
eduard256 1fc345c569 Add release process documentation 2025-12-11 16:52:53 +00:00
eduard256 0c0d743594 Merge develop into main for v1.0.9 release 2025-12-11 16:40:39 +00:00
eduard256 787919d20b Release v1.0.9: Fix SSE real-time streaming in Home Assistant Ingress mode 2025-12-11 16:40:31 +00:00
eduard256 e9dc04178e Fix SSE real-time streaming in Home Assistant Ingress mode
Add padding to overcome aiohttp 64KB buffer in HA Supervisor.

Problem:
- HA Supervisor uses aiohttp with 64KB StreamResponse buffer
- Small SSE events (~200-500 bytes) were buffered until connection closed
- Users saw all streams appear at once instead of real-time updates

Solution:
- Detect Ingress mode via X-Ingress-Path header
- Add 64KB SSE comment padding to fill proxy buffers
- Increase progress interval to 3 sec in Ingress mode (reduce traffic)
- Normal mode (Docker/direct) unchanged - works exactly as before

Traffic impact:
- Normal mode: ~17KB per scan (unchanged)
- Ingress mode: ~2-3MB per scan (acceptable for real-time updates)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-11 16:34:05 +00:00
eduard256 915c1dec1b Add stream categorization: Recommended/Alternative with Main/Sub/Other subgroups
- Split discovered streams into Recommended (FFMPEG, ONVIF) and Alternative groups
- Add Main/Sub/Other classification within Recommended based on resolution:
  - Main: streams with width >= 720px (after clustering analysis)
  - Sub: streams with width < 720px or lower cluster
  - Other: streams without resolution info
- Implement smart auto-collapse based on selection mode:
  - Main selection: shows Recommended/Main, collapses rest
  - Sub selection: shows Recommended/Sub, collapses rest
  - Falls back to showing all if target category is empty
- Add collapsible groups/subgroups with chevron toggles
- User manual expand/collapse preserved until mode change
- Add stream count badges to all group headers
2025-12-11 09:49:46 +00:00
eduard256 e6828d8a22 Add ?mp4 parameter support for BUBBLE streams in Frigate config
- Add buildRtspPath() helper method to conditionally append ?mp4
- Only BUBBLE stream types get ?mp4 suffix for proper recording
- Other stream types (RTSP, ONVIF, JPEG, etc.) remain unchanged
- Handles both single and dual-stream configurations correctly
2025-11-26 15:29:56 +03:00
eduard256 eedce14731 Merge branch 'develop' 2025-11-26 13:01:32 +03:00
eduard256 9975aa71de Release v1.0.8: Use host network mode for Docker deployments 2025-11-26 13:01:27 +03:00
eduard256 38e4af230f Use host network mode for Docker deployments
- Update docker run command to use --network host
- Update docker-compose.yml to use network_mode: host
- Update docker-compose.full.yml to use network_mode: host
- Remove port mappings as they are not needed with host network
2025-11-26 12:57:45 +03:00
eduard256 031e494787 Merge develop into main for v1.0.7 release 2025-11-23 22:54:20 +03:00
eduard256 de389588ce Release v1.0.7: Fix Hikvision channel numbering and improve database
- Fixed channel numbering for Hikvision-style cameras (reported by @sergbond_com)
- Added universal [CHANNEL+1] placeholder support
- Supports both 0-based and 1-based channel numbering
- Updated 14 camera brands with universal patterns
- Fixed brand+model search matching
- Removed invalid test data from database
2025-11-23 22:54:03 +03:00
eduard256 4c03ad8d3c Add [CHANNEL+1] placeholder support for Hikvision-style channel numbering
- Added [CHANNEL+1], [channel+1], {CHANNEL+1}, {channel+1} placeholders to builder.go
- Updated 14 camera brands with universal channel patterns
- Hikvision: replaced 10 hardcoded patterns with 6 universal patterns
- Hiwatch: replaced 4 hardcoded patterns with 8 universal patterns (including ISAPI)
- Other brands: Annke, Swann, Abus, 7links, LevelOne, AlienDVR, Oswoo, AV102IP-40, Acvil, TBKVision, Deltaco, Night Owl
- Universal patterns placed first for faster discovery, hardcoded patterns kept as fallback
- Supports both 0-based (channel=0 -> 101) and 1-based (channel=1 -> 101) numbering
- Added 6 high-priority patterns to popular_stream_patterns.json
2025-11-23 22:39:20 +03:00
eduard256 d569a76700 Use intelligent brand+model search in stream discovery 2025-11-23 21:33:44 +03:00
eduard256 a405d6198f Merge main into develop: Add dynamic channel support for HiWatch cameras 2025-11-22 22:22:41 +03:00
eduard256 4143c267cd Remove invalid URL entry from Hikvision database
- Removed entry with embedded credentials and IP address
- Entry contained: rtsp://huntertech:Superuser01!@10.0.55.11:554
- This was likely test data that accidentally got committed
- Model "Bullet-4K" entry removed from database
2025-11-22 21:52:53 +03:00
3757 changed files with 16136 additions and 277814 deletions
@@ -0,0 +1,316 @@
---
name: add_probe_detector_strix
description: Add a new device type detector to the Strix probe system. Covers adding new probers, result types, and detector functions.
disable-model-invocation: true
argument-hint: [detector-name]
---
# Add Probe Detector to Strix
You are adding a new device type detector to the Strix probe system. The probe system runs when a user enters an IP address -- it discovers what's at that IP and determines the device type. The device type drives the frontend flow.
The detector name is provided as argument (e.g. `/add_probe_detector_strix onvif`). If no argument, use AskUserQuestion to ask which detector to add.
## Repository
- Strix: `/home/user/Strix`
- go2rtc (reference): `/home/user/go2rtc`
---
## STEP 0: Understand the probe system
Before writing anything, read these files COMPLETELY:
```
/home/user/Strix/internal/probe/probe.go -- glue: Init(), runProbe(), detectors, API handler
/home/user/Strix/pkg/probe/models.go -- all data structures (Response, Probes, result types)
/home/user/Strix/pkg/probe/ping.go -- prober example: ICMP ping
/home/user/Strix/pkg/probe/ports.go -- prober example: TCP port scan
/home/user/Strix/pkg/probe/arp.go -- prober example: ARP lookup
/home/user/Strix/pkg/probe/dns.go -- prober example: reverse DNS
/home/user/Strix/pkg/probe/http.go -- prober example: HTTP HEAD request
/home/user/Strix/pkg/probe/mdns.go -- prober example: HomeKit mDNS query
/home/user/Strix/pkg/probe/oui.go -- prober example: OUI vendor lookup
```
Read ALL of them. Every prober is different. Understand the full picture before proceeding.
### How the probe system works
The probe has three layers:
**Layer 1: Probers** (`pkg/probe/`)
Pure functions that gather raw data about an IP address. Each runs in parallel with a shared 100ms timeout context. They do NOT interpret results -- just collect facts.
Current probers:
- `Ping()` -- ICMP echo, returns latency
- `ScanPorts()` -- TCP connect to all known camera ports, returns open ports
- `ReverseDNS()` -- reverse DNS lookup, returns hostname
- `LookupARP()` -- reads /proc/net/arp, returns MAC address
- `LookupOUI()` -- looks up MAC prefix in SQLite, returns vendor name
- `ProbeHTTP()` -- HTTP HEAD to ports 80/8080, returns status + server header
- `QueryHAP()` -- mDNS query for HomeKit Accessory Protocol, returns device info
Every prober writes its result into `resp.Probes.{Name}` via mutex.
**Layer 2: Detectors** (`internal/probe/probe.go`)
Functions registered in the `detectors` slice. They run AFTER all probers complete. Each detector receives the full `*probe.Response` with all probe results and returns a device type string (or empty string to pass).
```go
var detectors []func(*probe.Response) string
```
Detectors are checked in order. First non-empty result wins and sets `resp.Type`.
Default type is `"standard"`. If device is unreachable, type is `"unreachable"`.
**Layer 3: API** (`internal/probe/probe.go`)
`GET /api/probe?ip=192.168.1.100` returns the full Response JSON. The frontend uses `type` field to decide which UI flow to show.
### Data flow
```
IP address
|
v
[All probers run in parallel, 100ms timeout]
|
v
probe.Response filled with results
|
v
[Detectors run in order on the Response]
|
v
resp.Type = "homekit" | "standard" | "unreachable" | ...
|
v
JSON response to frontend
```
### API response example
```json
{
"ip": "192.168.1.100",
"reachable": true,
"latency_ms": 2.5,
"type": "homekit",
"probes": {
"ping": {"latency_ms": 2.5},
"ports": {"open": [80, 554, 5353]},
"dns": {"hostname": "camera.local"},
"arp": {"mac": "C0:56:E3:AA:BB:CC", "vendor": "Hikvision"},
"mdns": {
"name": "My Camera",
"device_id": "AA:BB:CC:DD:EE:FF",
"model": "Camera 1080p",
"category": "camera",
"paired": false,
"port": 80
},
"http": {"port": 80, "status_code": 200, "server": "nginx"}
}
}
```
---
## STEP 1: Determine what you need
Use AskUserQuestion to discuss with the user. There are two scenarios:
### Scenario A: Detector only (using existing probe data)
The detector can determine device type from data already collected by existing probers. No new prober needed.
Examples:
- Detect ONVIF cameras by checking if port 80 is open and HTTP server header contains "onvif" or specific vendor strings
- Detect specific brands by ARP vendor name
- Detect UPnP devices by checking specific open ports
In this case: skip to STEP 3.
### Scenario B: New prober + detector
Need to collect new data that existing probers don't provide. Requires adding a new prober to `pkg/probe/` and a new result type to `models.go`.
Examples:
- ONVIF discovery (send ONVIF GetCapabilities request)
- UPnP SSDP discovery
- Specific protocol handshake
In this case: proceed to STEP 2.
---
## STEP 2: Add new prober (Scenario B only)
### 2a: Add result type to models.go
Edit `/home/user/Strix/pkg/probe/models.go`:
1. Add new result struct:
```go
type {Name}Result struct {
// fields specific to this probe
}
```
2. Add field to `Probes` struct:
```go
type Probes struct {
Ping *PingResult `json:"ping"`
Ports *PortsResult `json:"ports"`
DNS *DNSResult `json:"dns"`
ARP *ARPResult `json:"arp"`
MDNS *MDNSResult `json:"mdns"`
HTTP *HTTPResult `json:"http"`
{Name} *{Name}Result `json:"{name}"` // add here
}
```
### 2b: Write prober function
Create `/home/user/Strix/pkg/probe/{name}.go`.
Rules:
- Pure function, no app/api imports
- Takes `context.Context` and `ip string` as first params
- Returns `(*{Name}Result, error)`
- Respects context deadline (timeout comes from runProbe)
- Returns `nil, nil` when device doesn't support this (NOT an error)
- Keep it simple -- one file, one function
Pattern:
```go
package probe
import "context"
func Probe{Name}(ctx context.Context, ip string) (*{Name}Result, error) {
// respect context deadline
deadline, ok := ctx.Deadline()
if !ok {
// set sensible default
}
// do the probe work...
// not supported = nil, nil (not an error)
// found = &{Name}Result{...}, nil
// actual error = nil, err
}
```
### 2c: Wire prober into runProbe
Edit `/home/user/Strix/internal/probe/probe.go`, add to `runProbe()` alongside other probers:
```go
run(func() {
r, _ := probe.Probe{Name}(ctx, ip)
mu.Lock()
resp.Probes.{Name} = r
mu.Unlock()
})
```
All probers run in parallel inside the same `run()` pattern. The mutex protects writes to `resp.Probes`.
---
## STEP 3: Add detector function
Edit `/home/user/Strix/internal/probe/probe.go`, add detector in `Init()`:
```go
// {Name} detector
detectors = append(detectors, func(r *probe.Response) string {
// check probe results to determine device type
// return type string or "" to pass
if r.Probes.{Something} != nil && {condition} {
return "{type_name}"
}
return ""
})
```
### Detector rules
1. Return a SHORT type string: `"homekit"`, `"onvif"`, `"tapo"`, etc.
2. Return `""` (empty) to pass to the next detector
3. Detectors run in order -- put more specific detectors BEFORE generic ones
4. A detector can use ANY combination of probe results (ports, HTTP, ARP, mDNS, custom)
5. Don't do network I/O in detectors -- all data should come from probers
### Type string convention
The type string is used by the frontend to select UI flow:
- `"unreachable"` -- device not found (set automatically, don't return this)
- `"standard"` -- default, normal camera (set automatically if no detector matches)
- `"homekit"` -- Apple HomeKit device
- Custom types: lowercase, one word, matches the protocol/brand name
---
## STEP 4: Build and test
```bash
cd /home/user/Strix
go build ./...
```
If it compiles, rebuild Docker and test:
```bash
docker build -t strix:test .
docker rm -f strix
docker run -d --name strix --network host --restart unless-stopped strix:test
sleep 2
# test probe on a known device
curl -s "http://localhost:4567/api/probe?ip={DEVICE_IP}" | python3 -m json.tool
```
Verify:
1. New probe data appears in `probes` object (if new prober added)
2. `type` field correctly identifies the device
3. No errors in `docker logs strix`
---
## STEP 5: Commit and push
```bash
cd /home/user/Strix
git add -A
git commit -m "Add {name} probe detector"
git push origin develop
```
---
## CODE STYLE
### pkg/probe/ files
- One file per prober
- Pure functions, no globals, no app imports
- `context.Context` as first param for anything with I/O
- Return `nil, nil` for "not applicable" (not an error)
- Short names: `conn`, `resp`, `buf`
### internal/probe/probe.go
- Detectors are inline anonymous functions in Init()
- Keep detector logic minimal -- just check fields and return type
- If detector logic is complex (>10 lines), extract to a named function in the same file
### models.go
- All result structs in one file
- JSON tags use lowercase with underscores
- Optional fields use `omitempty`
- Pointer types for probe results (nil = not collected)
+581
View File
@@ -0,0 +1,581 @@
---
name: add_protocol_strix
description: Add a new protocol support to Strix -- full flow from research to implementation. Covers stream handler registration, URL builder updates, database issues, and go2rtc integration.
disable-model-invocation: true
argument-hint: [protocol-name]
---
# Add Protocol to Strix
You are adding support for a new protocol to Strix. Follow every step in order. Be thorough -- read all referenced files completely before writing any code.
The protocol name is provided as argument (e.g. `/add_protocol_strix bubble`). If no argument, use AskUserQuestion to ask which protocol to add.
## Repositories
- Strix: `/home/user/Strix`
- go2rtc: `/home/user/go2rtc` (reference implementation, read-only)
- StrixCamDB: issues at https://github.com/eduard256/StrixCamDB/issues (for database updates)
---
## STEP 0: Understand the existing RTSP implementation (REFERENCE)
Before doing anything, read these files completely to understand the patterns:
```
/home/user/Strix/pkg/tester/source.go -- handler registry + RTSP reference implementation
/home/user/Strix/pkg/tester/worker.go -- how handlers are called, screenshot logic
/home/user/Strix/pkg/tester/session.go -- session data structures
/home/user/Strix/pkg/camdb/streams.go -- URL builder, placeholder replacement
/home/user/Strix/internal/test/test.go -- API layer for tester
/home/user/Strix/internal/search/search.go -- search API (rarely needs changes)
```
### How RTSP works (the reference pattern)
**Registration** in `pkg/tester/source.go`:
```go
var handlers = map[string]SourceHandler{}
func RegisterSource(scheme string, handler SourceHandler) {
handlers[scheme] = handler
}
func init() {
RegisterSource("rtsp", rtspHandler)
RegisterSource("rtsps", rtspHandler)
RegisterSource("rtspx", rtspHandler)
}
```
**Handler** -- receives a URL string, returns go2rtc `core.Producer`:
```go
func rtspHandler(rawURL string) (core.Producer, error) {
rawURL, _, _ = strings.Cut(rawURL, "#")
conn := rtsp.NewClient(rawURL)
conn.Backchannel = false
if err := conn.Dial(); err != nil {
return nil, fmt.Errorf("rtsp: dial: %w", err)
}
if err := conn.Describe(); err != nil {
_ = conn.Stop()
return nil, fmt.Errorf("rtsp: describe: %w", err)
}
return conn, nil
}
```
**Data flow**: URL -> GetHandler(url) -> handler(url) -> core.Producer -> GetMedias() -> codecs, latency -> getScreenshot() -> jpegSize() -> Result (with width, height)
**Key**: The handler ONLY needs to return a `core.Producer`. Everything else (codecs extraction, screenshot capture, session management) is handled automatically by `worker.go`.
### How URLs are built in `pkg/camdb/streams.go`:
1. Database has URL templates like `/cam/realmonitor?channel=[CHANNEL]&subtype=0`
2. `replacePlaceholders()` substitutes `[CHANNEL]`, `[USERNAME]`, `[PASSWORD]`, etc.
3. `buildURL()` prepends `protocol://user:pass@host:port` to the path
4. Credentials are URL-encoded with `url.PathEscape` / `url.QueryEscape`
Default ports are defined in `defaultPorts` map:
```go
var defaultPorts = map[string]int{
"rtsp": 554, "rtsps": 322, "http": 80, "https": 443,
"rtmp": 1935, "mms": 554, "rtp": 5004,
}
```
---
## STEP 1: Research the protocol in go2rtc
go2rtc already implements most camera protocols. Study the implementation:
### Where to look in go2rtc
| What | Where |
|------|-------|
| Protocol client logic | `/home/user/go2rtc/pkg/{protocol}/` |
| Module registration | `/home/user/go2rtc/internal/{protocol}/` |
| Core interfaces | `/home/user/go2rtc/pkg/core/core.go` |
| Stream handler registry | `/home/user/go2rtc/internal/streams/handlers.go` |
| Keyframe capture | `/home/user/go2rtc/pkg/magic/keyframe.go` |
### Protocol map in go2rtc
| Protocol | pkg/ (Dial function) | internal/ (Init glue) |
|----------|---------------------|----------------------|
| rtsp/rtsps | `pkg/rtsp/client.go` | `internal/rtsp/rtsp.go` |
| http/https | `pkg/magic/producer.go`, `pkg/tcp/request.go` | `internal/http/http.go` |
| rtmp | `pkg/rtmp/` | `internal/rtmp/rtmp.go` |
| bubble | `pkg/bubble/` | `internal/bubble/bubble.go` |
| dvrip | `pkg/dvrip/` | `internal/dvrip/dvrip.go` |
| onvif | `pkg/onvif/` | `internal/onvif/onvif.go` |
| homekit | `pkg/homekit/`, `pkg/hap/` | `internal/homekit/homekit.go` |
| tapo | `pkg/tapo/` | `internal/tapo/tapo.go` |
| kasa | `pkg/kasa/` | `internal/kasa/kasa.go` |
| eseecloud | `pkg/eseecloud/` | `internal/eseecloud/eseecloud.go` |
| nest | `pkg/nest/` | `internal/nest/init.go` |
| ring | `pkg/ring/` | `internal/ring/ring.go` |
| wyze | `pkg/wyze/` | `internal/wyze/wyze.go` |
| xiaomi | `pkg/xiaomi/` | `internal/xiaomi/xiaomi.go` |
| tuya | `pkg/tuya/` | `internal/tuya/tuya.go` |
| doorbird | `pkg/doorbird/` | `internal/doorbird/doorbird.go` |
| isapi | `pkg/isapi/` | `internal/isapi/init.go` |
| flussonic | `pkg/flussonic/` | `internal/flussonic/flussonic.go` |
| gopro | `pkg/gopro/` | `internal/gopro/gopro.go` |
| roborock | `pkg/roborock/` | `internal/roborock/roborock.go` |
### What to read
1. Read `/home/user/go2rtc/internal/{protocol}/{protocol}.go` -- find `streams.HandleFunc` call, understand what function is called and how
2. Read `/home/user/go2rtc/pkg/{protocol}/` -- find the `Dial()` or `NewClient()` function, understand its signature and what it returns
3. Understand: does it return `core.Producer`? Does it need special setup before Dial? Does it need credentials differently?
### Typical go2rtc internal module (e.g. kasa -- simplest):
```go
package kasa
import (
"github.com/AlexxIT/go2rtc/internal/streams"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/kasa"
)
func Init() {
streams.HandleFunc("kasa", func(source string) (core.Producer, error) {
return kasa.Dial(source)
})
}
```
Most protocols follow this exact pattern: `pkg/{protocol}.Dial(url)` returns `core.Producer`.
---
## STEP 2: Classify the protocol
Use AskUserQuestion to discuss with the user. Determine the protocol type:
### Type A: Standard URL-based protocol (rtsp, rtmp, bubble, dvrip, http, etc.)
- Has URL scheme (e.g. `bubble://host:port/path`)
- URLs stored in StrixCamDB database
- Flow: user searches camera -> gets URL templates -> URLs built with credentials -> sent to tester
- Needs: stream handler in tester + default port in URL builder + database issue
### Type B: Custom/discovery protocol (homekit, onvif, etc.)
- Does NOT use standard URL templates from database
- Has custom discovery or authentication flow
- Data comes from probe endpoint or direct user input, NOT from camera search
- Needs: source handler in tester with custom logic, possibly probe endpoint update
- Does NOT need database issue
### Type C: HTTP sub-protocol (mjpeg, jpeg snapshot, hls)
- Uses http:// or https:// URL scheme
- Already has URLs in database (same as HTTP)
- Needs special handling in tester based on Content-Type response
- Needs: stream handler that detects content type and handles accordingly
---
## STEP 3: For Type A -- Create StrixCamDB issue
ONLY for Type A protocols that have URL patterns stored in the database.
Create a GitHub issue using `gh` CLI for the new protocol:
```bash
cd /home/user/Strix
gh issue create --repo eduard256/StrixCamDB \
--title "[New Protocol] {PROTOCOL_NAME}" \
--label "new-protocol" \
--body "$(cat <<'ISSUE_EOF'
```yaml
protocol: {PROTOCOL_NAME}
default_port: {PORT}
url_format: {EXAMPLE_URL_PATTERN}
```
## Description
{DESCRIPTION -- what cameras use this, what firmware, how it works}
## Known brands
- {BRAND1}
- {BRAND2}
## URL patterns
- {PATTERN1} -- main stream
- {PATTERN2} -- sub stream
## Where to research
- go2rtc source: https://github.com/AlexxIT/go2rtc/tree/master/pkg/{PROTOCOL_NAME}
- ispyconnect: search for "{PROTOCOL_NAME}" cameras
## Notes
{ANY_NOTES}
ISSUE_EOF
)"
```
If the protocol introduces new placeholders (e.g. `[STREAM]`), create a separate issue:
```bash
gh issue create --repo eduard256/StrixCamDB \
--title "[New Placeholder] {PLACEHOLDER}" \
--label "new-placeholder" \
--body "$(cat <<'ISSUE_EOF'
placeholder: "{PLACEHOLDER}"
alternatives: ["{alt1}", "{alt2}"]
description: "{WHAT_IT_DOES}"
example_values: ["{VAL1}", "{VAL2}"]
## URL examples
- {URL_EXAMPLE_1}
- {URL_EXAMPLE_2}
## Known brands using this
- {BRAND1}
- {BRAND2}
ISSUE_EOF
)"
```
DO NOT wait for issue approval. Continue immediately to the next step.
---
## STEP 4: Update URL builder (Type A only)
If the protocol needs a new default port, edit `/home/user/Strix/pkg/camdb/streams.go`:
Add the port to `defaultPorts` map:
```go
var defaultPorts = map[string]int{
"rtsp": 554, "rtsps": 322, "http": 80, "https": 443,
"rtmp": 1935, "mms": 554, "rtp": 5004,
// add new protocol here:
"bubble": 80,
}
```
If the protocol needs new placeholders in `replacePlaceholders()`, add them to the pairs slice. Follow the existing pattern -- both `[UPPER]` and `[lower]` variants, plus `{curly}` variants.
### Files to edit for URL builder:
- `/home/user/Strix/pkg/camdb/streams.go` -- `defaultPorts` map and `replacePlaceholders()` function
---
## STEP 5: Add stream handler to tester
### Before writing code
1. Read ALL existing handlers in `/home/user/Strix/pkg/tester/source.go` completely
2. Read the go2rtc pkg/ implementation for this protocol (Step 1)
3. Understand what the `Dial()` function needs and returns
### For standard protocols (Type A, most Type C)
Most protocols follow the same pattern as RTSP. The handler:
1. Takes a URL string
2. Calls go2rtc's `pkg/{protocol}.Dial(url)` or equivalent
3. Returns `core.Producer`
Add the handler to `/home/user/Strix/pkg/tester/source.go`.
**Pattern for simple protocols** (bubble, dvrip, rtmp, kasa, etc.):
```go
import "github.com/AlexxIT/go2rtc/pkg/{protocol}"
// in init():
RegisterSource("{scheme}", {scheme}Handler)
// handler:
func {scheme}Handler(rawURL string) (core.Producer, error) {
return {protocol}.Dial(rawURL)
}
```
If the protocol needs extra setup before Dial (like RTSP needs `Backchannel = false`), add it. Study the go2rtc internal module to see what setup is done.
**Pattern for protocols that need connection setup** (like RTSP):
```go
func {scheme}Handler(rawURL string) (core.Producer, error) {
rawURL, _, _ = strings.Cut(rawURL, "#")
conn := {protocol}.NewClient(rawURL)
// any setup specific to this protocol
if err := conn.Dial(); err != nil {
return nil, fmt.Errorf("{scheme}: dial: %w", err)
}
// protocol-specific validation (like RTSP Describe)
return conn, nil
}
```
### For custom protocols (Type B -- homekit, onvif, etc.)
These protocols do NOT go through the standard URL -> handler flow. They need a **source handler** that receives custom parameters and produces results directly.
The current architecture uses `SourceHandler func(rawURL string) (core.Producer, error)` for standard protocols. For custom protocols, you need to:
1. Extend the POST /api/test request to accept custom source blocks
2. Handle them separately from the `streams` array
Current request format:
```json
{
"sources": {
"streams": ["rtsp://...", "http://..."]
}
}
```
Extended format for custom protocols:
```json
{
"sources": {
"streams": ["rtsp://...", "http://..."],
"homekit": {"device_id": "AA:BB:CC", "pin": "123-45-678"},
"onvif": {"host": "192.168.1.100", "username": "admin", "password": "pass"}
}
}
```
To implement this:
1. Define a source handler type in `/home/user/Strix/pkg/tester/source.go`:
```go
// SourceBlockHandler processes a custom source block, writes results directly to session
type SourceBlockHandler func(data json.RawMessage, s *Session)
var sourceHandlers = map[string]SourceBlockHandler{}
func RegisterSourceBlock(name string, handler SourceBlockHandler) {
sourceHandlers[name] = handler
}
```
2. Update `/home/user/Strix/internal/test/test.go` `apiTestCreate()` to parse and dispatch custom source blocks.
3. Write the handler for your protocol. It receives raw JSON and a Session, and is responsible for:
- Parsing its own parameters
- Running its own discovery/test logic
- Adding Results to the Session
- Calling `s.AddTested()` for progress tracking
**IMPORTANT**: Before implementing a custom protocol, discuss the approach with the user. Custom protocols are rare and need careful design.
---
## STEP 6: Test the implementation
### Build and verify
```bash
cd /home/user/Strix
go build ./...
```
If it compiles, test with the running container:
```bash
# rebuild image
docker build -t strix:test .
# restart container
docker rm -f strix
docker run -d --name strix --network host --restart unless-stopped strix:test
# check logs
docker logs strix
# test the new protocol (example for bubble)
curl -s -X POST http://localhost:4567/api/test \
-H 'Content-Type: application/json' \
-d '{"sources":{"streams":["bubble://admin:password@192.168.1.100:80/"]}}'
```
### What to verify
1. Handler is registered -- check logs for no errors at startup
2. URLs with the new scheme are dispatched to the correct handler
3. If Type A: verify `/api/streams` returns URLs with correct scheme and port
4. Test with a real device if available
---
## STEP 7: Commit and push
```bash
cd /home/user/Strix
git add -A
git commit -m "Add {protocol} protocol support
- Register {protocol} stream handler using go2rtc pkg/{protocol}
- Add default port {port} for {protocol} scheme
- {any other changes}"
git push origin develop
```
---
## CODE STYLE RULES
All code MUST follow AlexxIT go2rtc style:
### File organization
- One handler per protocol is fine in `source.go` if it's a one-liner (`return pkg.Dial(url)`)
- If handler needs >10 lines of custom logic, create `source_{protocol}.go`
- Keep `source.go` as the registry + simple handlers
- Complex protocols get their own file
### Naming
- Handler: `{scheme}Handler` (e.g. `bubbleHandler`, `rtmpHandler`)
- Error prefix: `"{scheme}: dial: ..."` or `"{scheme}: ..."`
- Short var names: `conn` for connection, `prod` for producer
### Error handling
- Wrap errors with protocol prefix: `fmt.Errorf("bubble: dial: %w", err)`
- Close/stop connections on error: `_ = conn.Stop()`
- Return nil Producer on error, never a half-initialized one
### Comments
- Comment ONLY if the "why" is not obvious
- No docstrings on every function
- Inline examples: `// ex. "bubble://admin:pass@192.168.1.100:80/"`
### Imports
- go2rtc packages: `"github.com/AlexxIT/go2rtc/pkg/{protocol}"`
- Always import `"github.com/AlexxIT/go2rtc/pkg/core"` for Producer interface
- Group: stdlib, then go2rtc, then project packages
---
## go2rtc INTERNALS REFERENCE
### core.Producer interface (pkg/core/core.go)
Every protocol handler must return something that implements `core.Producer`:
```go
type Producer interface {
GetMedias() []*Media // what tracks are available (video/audio codecs)
GetTrack(media *Media, codec *Codec) (*Receiver, error) // get specific track
Start() error // start receiving packets (blocking)
Stop() error // close connection
}
```
The tester uses:
1. `GetMedias()` -- to list codecs (H264, AAC, etc.)
2. `GetTrack()` + `Start()` -- to capture screenshot (keyframe)
3. `Stop()` -- to clean up
### How screenshot and resolution work (pkg/tester/worker.go)
1. `getScreenshot(prod)` is called after successful Dial
2. Creates `magic.NewKeyframe()` consumer
3. Matches video media between producer and consumer
4. Gets track via `prod.GetTrack()`
5. Starts `prod.Start()` in goroutine (blocking -- reads packets)
6. Waits for first keyframe via `cons.WriteTo()` with 10s timeout
7. If H264/H265 -- converts to JPEG via ffmpeg
8. If already JPEG -- uses as-is
9. `jpegSize(jpeg)` extracts width and height from JPEG SOF0/SOF2 marker
10. Resolution stored in `Result.Width` and `Result.Height`
This works automatically for ANY protocol that returns a valid `core.Producer`. You do NOT need to implement screenshot or resolution logic per protocol.
### Result struct (pkg/tester/session.go)
```go
type Result struct {
Source string `json:"source"`
Screenshot string `json:"screenshot,omitempty"`
Codecs []string `json:"codecs,omitempty"`
Width int `json:"width,omitempty"` // from JPEG screenshot
Height int `json:"height,omitempty"` // from JPEG screenshot
LatencyMs int64 `json:"latency_ms,omitempty"`
Skipped bool `json:"skipped,omitempty"`
}
```
Resolution is extracted from the JPEG screenshot, not from SDP or protocol-specific data. This means width/height are only available when a screenshot was successfully captured. The frontend uses these values to classify streams as Main (HD) or Sub (SD).
### magic.NewKeyframe() (pkg/magic/keyframe.go)
Captures first video keyframe from any Producer. Supports H264, H265, JPEG, MJPEG. The tester uses this -- you never call it directly from a protocol handler.
### Connection patterns in go2rtc
**Simple Dial** (most protocols):
```go
// pkg/bubble/client.go
func Dial(rawURL string) (core.Producer, error) {
// parse URL, connect, return producer
}
```
**Client with setup** (rtsp):
```go
// pkg/rtsp/client.go
conn := rtsp.NewClient(rawURL)
conn.Backchannel = false // optional setup
conn.Dial() // TCP connect
conn.Describe() // RTSP DESCRIBE (gets SDP)
// conn is now a Producer
```
**HTTP-based** (complex -- content type detection):
```go
// pkg/magic/producer.go
// Opens HTTP connection, detects Content-Type:
// - multipart/x-mixed-replace -> MJPEG
// - image/jpeg -> single JPEG frame
// - application/vnd.apple.mpegurl -> HLS
// - video/mp2t -> MPEG-TS
// - etc.
```
### TCP/TLS connection (pkg/tcp/)
Many protocols use `pkg/tcp` for low-level connection:
- `tcp.Dial(rawURL)` -- TCP connect with timeout
- `tcp.Client` -- HTTP client with digest/basic auth
- Used by RTSP, HTTP, and others internally
---
## CHECKLIST BEFORE FINISHING
- [ ] Read all existing protocol handlers in `source.go`
- [ ] Read go2rtc pkg/ and internal/ for this protocol
- [ ] Determined protocol type (A/B/C)
- [ ] For Type A: created StrixCamDB issue (protocol + placeholders if needed)
- [ ] For Type A: added default port to `defaultPorts` in `streams.go` (if not already there)
- [ ] Added handler registration in `source.go` init() or new file
- [ ] Handler follows RTSP pattern: Dial -> return Producer
- [ ] Error messages prefixed with protocol name
- [ ] Connections closed on error
- [ ] Code compiles: `go build ./...`
- [ ] Committed and pushed to develop
@@ -0,0 +1,211 @@
---
name: frontend_design_strix
description: Create or redesign frontend pages for Strix. Use when building new HTML pages, redesigning existing ones, or working on any UI task in the www/ directory. Covers design principles, layout patterns, and component usage.
disable-model-invocation: true
---
# Strix Frontend Design
You are creating or modifying a frontend page for Strix. Your goal is to produce a page that looks **identical in quality** to the existing pages, especially `www/homekit.html` which is the design reference.
## Before you start
Read these files completely:
1. **`www/design-system.html`** -- All CSS variables, every component, JS patterns. This is your component library.
2. **`www/homekit.html`** -- The design reference. This page is the gold standard. Study its structure, spacing, how little text it uses, how the back button is positioned.
3. **`www/index.html`** -- The entry point. Understand the probe flow and how data is passed between pages via URL params.
If you need to understand backend APIs or the probe system, read:
- `www/standard.html` -- how probe data flows into a configuration page
- `www/test.html` -- how polling and real-time updates work
- `www/config.html` -- complex two-column layout with live preview
## Design Philosophy
### Radical minimalism
Every element on screen must earn its place. If something doesn't help the user complete their task, remove it.
- **10% text, 90% meaning.** A label that says "Pairing Code" with an info-icon is better than a paragraph explaining what a pairing code is.
- **Hide details behind info-icons.** Long explanations go into tooltips (the `(i)` icon pattern). The user who needs the explanation can hover. The user who doesn't is not bothered.
- **No decorative elements without function.** No ornamental icons, no badges that don't convey information, no cards-as-decoration.
- **One action per screen.** Each page should have one primary thing the user does. Everything else is secondary.
### How we think about design decisions
When building homekit.html, we went through this process:
1. **Started with all the data** -- device info table, long descriptions, badges, decorative icons
2. **Asked "does the user need this?"** for every element
3. **Removed everything that wasn't essential** -- the device info table (IP, MAC, vendor) was removed because the user doesn't need it to enter a PIN code
4. **Moved explanations into tooltips** -- "This camera supports Apple HomeKit. Enter the 8-digit pairing code printed on your camera or included in the manual" became just a label "Pairing Code" with a tooltip
5. **Removed format hints** -- "Format: XXX-XX-XXX" was removed because the input fields themselves make the format obvious
6. **Made the primary action obvious** -- big button, full width, impossible to miss
Apply this same thinking to every page you create.
### Visual rules
- Dark theme with purple accent -- never deviate from the color palette in `:root`
- All icons are inline SVG -- never use emoji, never use icon fonts, never use external icon libraries
- Fonts: system font stack for UI, monospace for technical values (URLs, IPs, codes)
- Borders are subtle: `rgba(139, 92, 246, 0.15)` -- barely visible purple tint
- Glow effects on focus and hover, never on static elements (except logos)
- Animations are fast (150ms) and subtle -- translateY(-2px) on hover, fadeIn on page load
- No rounded corners larger than 8px (except special cases like toggle switches)
## Layout Patterns
### Pages after probe (like homekit.html) -- TRUE CENTER
This is the most common case for new pages. Content is vertically centered on screen.
```
.screen {
min-height: 100vh;
display: flex;
align-items: center; /* TRUE CENTER -- not flex-start */
justify-content: center;
}
.container { max-width: 480px; width: 100%; }
```
**Back button** is positioned OUTSIDE the container, wider than content, using `.back-wrapper`:
```
.back-wrapper {
position: absolute; top: 1.5rem;
left: 50%; transform: translateX(-50%);
width: 100%; max-width: 600px; /* wider than container */
padding: 0 1.5rem;
z-index: 10;
}
```
This is MANDATORY for all centered layout pages. The back button must NOT be inside the centered container.
### Entry page (like index.html) -- TOP CENTER
Content is near the top with `margin-top: 8vh`. Used for the main entry point only.
### Content pages (like standard.html, create.html) -- STANDARD
Back button at top, then title, then content flowing down. `max-width: 600px`, no vertical centering.
### Data-heavy pages (like test.html) -- WIDE
`max-width: 1200px` with card grids.
### Two-column (like config.html) -- SPLIT
Settings left, live preview right. Collapses to tabs on mobile.
## Hero Section Pattern
For centered pages, the hero contains a logo/icon + short title:
```html
<div class="hero">
<svg class="logo-icon">...</svg> <!-- 48-72px, with glow filter -->
<h1 class="title">Short Name</h1> <!-- 1.25rem, white, font-weight 600 -->
</div>
```
- The icon should be recognizable and relevant (Strix owl for main, HomeKit house for HomeKit)
- The title is SHORT -- one or two words max
- No subtitles unless absolutely necessary
- Glow effect on the icon via `filter: drop-shadow()`
## Component Usage
All components are documented with live examples in `www/design-system.html`. Key ones:
- **Buttons**: `.btn .btn-primary .btn-large` for primary action (full width), `.btn-outline` for secondary
- **Inputs**: `.input` with `.label` and optional `.info-icon` with `.tooltip`
- **Toast**: Every page needs `<div id="toast" class="toast hidden"></div>` and the `showToast()` function
- **Error box**: `.error-box` with `.visible` class toggled
- **Info icon + tooltip**: For hiding explanations -- always prefer this over visible text
## Navigation -- CRITICAL
### Always pass ALL known data forward
When navigating to another page, pass every piece of data you have. This is non-negotiable. Future pages may need any of these values.
```javascript
function navigateNext() {
var p = new URLSearchParams();
p.set('primary_data', value);
// Pass through EVERYTHING known:
if (ip) p.set('ip', ip);
if (mac) p.set('mac', mac);
if (vendor) p.set('vendor', vendor);
if (model) p.set('model', model);
if (server) p.set('server', server);
if (hostname) p.set('hostname', hostname);
if (ports) p.set('ports', ports);
if (user) p.set('user', user);
if (channel) p.set('channel', channel);
// ... any other params from probe
window.location.href = 'next.html?' + p.toString();
}
```
### Page init always reads all params
```javascript
var params = new URLSearchParams(location.search);
var ip = params.get('ip') || '';
var mac = params.get('mac') || '';
var vendor = params.get('vendor') || '';
// ... read ALL possible params even if this page doesn't use them
// They need to be available for passing to the next page
```
## JavaScript Rules
- Use `var`, not `let`/`const` -- ES5 compatible
- Build DOM with `document.createElement`, not innerHTML
- Use `async function` + `fetch()` for API calls
- Always handle errors: check `!r.ok`, catch exceptions, show toast
- Debounce input handlers if they trigger API calls (300ms)
- Use `addEventListener`, never inline event handlers in HTML
## API Pattern
```javascript
async function doSomething() {
try {
var r = await fetch('api/endpoint', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!r.ok) {
var text = await r.text();
showToast(text || 'Error ' + r.status);
return;
}
var data = await r.json();
// success...
} catch (e) {
showToast('Connection error: ' + e.message);
}
}
```
## Checklist before finishing
- [ ] Page uses correct layout pattern for its type
- [ ] Back button positioned correctly (`.back-wrapper` for centered, inline for standard)
- [ ] All CSS variables from `:root` -- no hardcoded colors
- [ ] No unnecessary text -- everything possible hidden behind info-icons
- [ ] All known URL params are read at init and passed forward on navigation
- [ ] Toast element present, showToast function included
- [ ] Error states handled (API errors, validation)
- [ ] Mobile responsive (test at 375px width)
- [ ] No emoji anywhere
- [ ] All icons are inline SVG
- [ ] Primary action is obvious and full-width
- [ ] Page looks like it belongs with homekit.html and index.html
+209
View File
@@ -0,0 +1,209 @@
---
name: release_strix
description: Full release of Strix -- merge develop to main, tag, build multiarch Docker image, build static binaries, push to Docker Hub, update hassio-strix, create GitHub Release with binaries attached.
disable-model-invocation: true
---
# Strix Release
You are performing a full release of Strix. Follow every step exactly. Do NOT skip steps. Do NOT ask for confirmation except where explicitly noted below.
## Repositories
- Strix: `/home/user/Strix`
- hassio-strix: `/home/user/hassio-strix`
## Versioning
Version is injected at build time via ldflags (`-X main.version=$VERSION`). There is NO hardcoded version in the source code -- `main.go` has `var version = "dev"` as default. The Dockerfile passes `--build-arg VERSION` which maps to the same ldflags. Do NOT edit `main.go` to set the version.
## Step 1: Gather information
```bash
cd /home/user/Strix
git checkout develop
git pull origin develop
git pull origin main
# Get last release tag
git tag --sort=-version:refname | head -1
# Show all commits since last release
git log main..develop --oneline
# Show changed files
git diff main..develop --stat
```
## Step 2: Ask for version (THE ONLY QUESTION)
Use AskUserQuestion to ask the user which version to release.
Show them:
- The last tag
- The list of commits from Step 1
Offer options:
- Next patch (e.g. 1.0.9 -> 1.0.10)
- Next minor (e.g. 1.0.9 -> 1.1.0)
- Next major (e.g. 1.0.9 -> 2.0.0)
- Other (user types custom version)
Wait for answer. Store the chosen version as VERSION (without "v" prefix).
## Step 3: Download latest camera database
```bash
cd /home/user/Strix
gh release download latest --repo eduard256/StrixCamDB --pattern "cameras.db" --clobber
```
Verify the database was downloaded:
```bash
ls -lh cameras.db
```
## Step 4: Verify build
```bash
cd /home/user/Strix
go test ./...
CGO_ENABLED=0 go build ./...
```
If tests or build fail -- STOP and report the error. Do not continue.
## Step 5: Update CHANGELOG.md
Read `/home/user/Strix/CHANGELOG.md`. Add a new section at the top (after the header lines), based on the commits from Step 1. Follow the existing format exactly:
```markdown
## [VERSION] - YYYY-MM-DD
### Added
- ...
### Fixed
- ...
### Changed
- ...
```
Use today's date. Categorize commits into Added/Fixed/Changed/Technical sections. Only include sections that have entries. Write clear, user-facing descriptions (not raw commit messages).
## Step 6: Git -- commit, merge, tag, push
```bash
cd /home/user/Strix
git add CHANGELOG.md
git commit -m "Release v$VERSION"
git checkout main
git merge develop --no-ff -m "Merge develop into main for v$VERSION release"
git tag v$VERSION
git push origin main --tags
git checkout develop
git merge main
git push origin develop
```
## Step 7: Build and push Docker image
```bash
cd /home/user/Strix
docker buildx build --platform linux/amd64,linux/arm64 \
--build-arg VERSION=$VERSION \
-t eduard256/strix:$VERSION \
-t eduard256/strix:latest \
-t eduard256/strix:$(echo $VERSION | cut -d. -f1-2) \
-t eduard256/strix:$(echo $VERSION | cut -d. -f1) \
--push .
```
## Step 8: Verify Docker Hub
```bash
curl -s "https://hub.docker.com/v2/repositories/eduard256/strix/tags/?page_size=10" | jq '.results[].name'
docker manifest inspect eduard256/strix:$VERSION | jq '.manifests[].platform'
```
Verify the new version tag exists and both amd64 and arm64 platforms are present.
## Step 9: Smoke test
```bash
docker run --rm -d --name strix-smoke-test -p 14567:4567 eduard256/strix:$VERSION
sleep 5
curl -s http://localhost:14567/api | jq '.version'
docker stop strix-smoke-test
```
Verify the health endpoint returns the correct version string.
## Step 10: Update hassio-strix
```bash
cd /home/user/hassio-strix
git pull origin main
```
Edit `/home/user/hassio-strix/strix/config.json` -- change `"version"` to the new VERSION.
Edit `/home/user/hassio-strix/strix/CHANGELOG.md` -- add the same CHANGELOG section as in Step 5.
```bash
cd /home/user/hassio-strix
git add strix/config.json strix/CHANGELOG.md
git commit -m "Release v$VERSION"
git push origin main
```
## Step 11: Build static binaries
Build static binaries for both platforms:
```bash
cd /home/user/Strix
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.version=$VERSION" -o strix-linux-amd64 .
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X main.version=$VERSION" -o strix-linux-arm64 .
```
Verify both binaries are statically linked:
```bash
file strix-linux-amd64 strix-linux-arm64
```
## Step 12: GitHub Release
Create the release and attach binaries:
```bash
cd /home/user/Strix
PREV_TAG=$(git tag --sort=-version:refname | sed -n '2p')
gh release create v$VERSION \
--title "v$VERSION" \
--notes "$(git log --oneline ${PREV_TAG}..v$VERSION)" \
strix-linux-amd64 strix-linux-arm64
```
Clean up binaries after upload:
```bash
rm -f strix-linux-amd64 strix-linux-arm64
```
## Step 13: Final report
Output a summary:
```
Release v$VERSION complete:
- Git: tag v$VERSION pushed to main
- Docker Hub: eduard256/strix:$VERSION (amd64 + arm64)
- Health check: version "$VERSION" verified
- Binaries: strix-linux-amd64, strix-linux-arm64 attached to GitHub Release
- hassio-strix: config.json updated to $VERSION, pushed to main
- GitHub Release: <URL from gh release create>
```
+72
View File
@@ -0,0 +1,72 @@
---
name: release_strix_dev
description: Build and push dev Docker image for Strix, update hassio-strix dev add-on version.
disable-model-invocation: true
---
# Strix Dev Build
You are building and pushing a dev image of Strix. Follow every step exactly. Do NOT ask any questions -- this is fully automated.
## Repositories
- Strix: `/home/user/Strix`
- hassio-strix: `/home/user/hassio-strix`
## Step 1: Get commit hash
```bash
cd /home/user/Strix
git rev-parse --short HEAD
```
Store this as COMMIT_HASH (e.g. `fe93aa3`).
## Step 2: Download latest camera database
```bash
cd /home/user/Strix
gh release download latest --repo eduard256/StrixCamDB --pattern "cameras.db" --clobber
ls -lh cameras.db
```
## Step 3: Build Docker image
```bash
cd /home/user/Strix
docker build --build-arg VERSION=dev-$COMMIT_HASH -t eduard256/strix:dev -t eduard256/strix:dev-$COMMIT_HASH .
```
## Step 4: Push to Docker Hub
```bash
docker push eduard256/strix:dev
docker push eduard256/strix:dev-$COMMIT_HASH
```
## Step 5: Update hassio-strix
```bash
cd /home/user/hassio-strix
git pull origin main
```
Edit `/home/user/hassio-strix/strix-dev/config.json` -- change `"version"` to `dev-$COMMIT_HASH`.
```bash
cd /home/user/hassio-strix
git add strix-dev/config.json
git commit -m "Dev build dev-$COMMIT_HASH"
git push origin main
```
## Step 6: Report
Output a summary:
```
Dev build complete:
- Commit: $COMMIT_HASH
- Docker Hub: eduard256/strix:dev, eduard256/strix:dev-$COMMIT_HASH (amd64)
- hassio-strix: strix-dev version updated to dev-$COMMIT_HASH
```
-52
View File
@@ -1,52 +0,0 @@
# Git
.git
.gitignore
.github
# IDE
.vscode
.idea
*.swp
*.swo
*~
# Build artifacts
bin/
dist/
*.exe
*.dll
*.so
*.dylib
# Test files
*.test
*_test.go
coverage.*
*.out
# Logs
*.log
strix.log
# Config files (user-specific)
strix.yaml
test_*.yaml
config.yaml
# Temporary files
tmp/
temp/
*.dump
*_output.txt
# Documentation (included in image metadata instead)
*.md
!README.md
# OS files
.DS_Store
Thumbs.db
# Development
.env
.env.local
-54
View File
@@ -1,54 +0,0 @@
name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Cache Go modules
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Download dependencies
run: go mod download
- name: Run tests
run: go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
- name: Build
run: make build
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: latest
-77
View File
@@ -1,77 +0,0 @@
name: Docker Build and Push
on:
push:
branches:
- main
tags:
- 'v*'
pull_request:
branches:
- main
env:
REGISTRY: docker.io
IMAGE_NAME: eduard256/strix
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
VERSION=${{ steps.meta.outputs.version }}
- name: Docker Hub Description
if: github.event_name != 'pull_request'
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
repository: ${{ env.IMAGE_NAME }}
readme-filepath: ./README.md
short-description: "Smart IP Camera Stream Discovery System"
-32
View File
@@ -1,32 +0,0 @@
name: Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+5 -48
View File
@@ -1,50 +1,7 @@
# Binaries # Binary
bin/
strix strix
main
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binaries # SQLite database files
*.test *.db
*.db-shm
# Output of the go coverage tool *.db-wal
*.out
coverage.html
# Go workspace file
go.work
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Logs
*.log
# Environment
.env
.env.local
# Temporary files
tmp/
temp/
*.dump
*_output.txt
# Configuration (user-specific)
strix.yaml
# Node.js / NPM
node_modules/
package-lock.json
-112
View File
@@ -1,112 +0,0 @@
# GoReleaser configuration for Strix
version: 2
before:
hooks:
- go mod tidy
- go mod download
builds:
- id: strix
main: ./cmd/strix/main.go
binary: strix
env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
- arm
goarm:
- "7"
ignore:
- goos: windows
goarch: arm
- goos: darwin
goarch: arm
ldflags:
- -s -w
- -X main.Version={{.Version}}
- -X main.BuildDate={{.Date}}
- -X main.GitCommit={{.ShortCommit}}
archives:
- id: strix-archive
format: tar.gz
name_template: >-
{{ .ProjectName }}_
{{- .Version }}_
{{- .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
format_overrides:
- goos: windows
format: zip
files:
- README.md
- LICENSE
- webui/**/*
- cameras/**/*
checksum:
name_template: 'checksums.txt'
algorithm: sha256
changelog:
sort: asc
use: github
filters:
exclude:
- '^docs:'
- '^test:'
- '^chore:'
- typo
groups:
- title: '🚀 Features'
regexp: '^.*?feat(\([[:word:]]+\))??!?:.+$'
order: 0
- title: '🐛 Bug Fixes'
regexp: '^.*?fix(\([[:word:]]+\))??!?:.+$'
order: 1
- title: '📝 Documentation'
regexp: '^.*?docs(\([[:word:]]+\))??!?:.+$'
order: 2
- title: '🔧 Other'
order: 999
release:
github:
owner: eduard256
name: Strix
draft: false
prerelease: auto
name_template: "v{{.Version}}"
header: |
## 🦉 Strix v{{.Version}}
Smart IP Camera Stream Discovery System
### Installation
Download the appropriate binary for your platform below and extract it.
### Usage
```bash
./strix
```
Then open http://localhost:4567 in your browser.
footer: |
**Full Changelog**: https://github.com/eduard256/Strix/compare/{{ .PreviousTag }}...{{ .Tag }}
snapshot:
name_template: "{{ incpatch .Version }}-next"
dist: dist
+42 -27
View File
@@ -1,33 +1,48 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file. ## [2.1.0] - 2026-04-08
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.1.0] - 2025-11-06
### Added ### Added
- 🦉 Initial release of Strix - ONVIF protocol support: auto-discovery via unicast WS-Discovery, stream resolution through ONVIF profiles
- 🌐 Web-based user interface for camera stream discovery - ONVIF probe detector: detects ONVIF cameras during network probe (4-7ms response time, no auth required)
- 🔍 Automatic RTSP stream discovery for IP cameras - ONVIF camera page (onvif.html): credentials form with option to also test popular stream patterns
- 📹 Support for multiple camera manufacturers - ONVIF stream handler: resolves all camera profiles, tests each via RTSP, returns paired results (onvif:// + rtsp://) with shared screenshots
- 🎯 ONVIF device discovery and PTZ endpoint detection - Design system reference (design-system.html) with all UI components documented
- 🔐 Credential embedding in stream URLs
- 📊 Camera model database with autocomplete search
- 🎨 Modern, responsive UI with purple owl logo
- ⚙️ Configuration export for Go2RTC and Frigate
- 🔄 Dual-stream support with optional sub-stream selection
- 📡 Server-Sent Events (SSE) for real-time discovery progress
- 🚀 RESTful API for camera search and stream discovery
- 📦 Cross-platform support (Linux, Windows, macOS)
- 🏗️ Built with Go for high performance
### Features ### Changed
- **Web Interface**: Clean, intuitive UI for camera configuration - ONVIF has highest probe priority (above HomeKit and Standard)
- **Stream Discovery**: Automatically finds working RTSP streams - JPEG-only streams (no H264/H265) are classified as Alternative in test results
- **ONVIF Support**: Discovers ONVIF devices and PTZ capabilities - HomeKit page redesigned: Apple HomeKit logo, centered layout, floating back button
- **Multi-Platform**: Binaries for Linux (amd64, arm64, arm/v7), Windows, and macOS - Hardened create.html against undefined/null URL values in query parameters
- **Easy Integration**: Export configs for popular NVR systems
[0.1.0]: https://github.com/eduard256/Strix/releases/tag/v0.1.0 ## [2.0.0] - 2025-04-05
### Added
- Complete rewrite as a single Go binary with modular architecture
- DVRIP protocol support
- RTMP protocol support
- Bubble protocol support
- HTTP/HTTPS protocol support for snapshots and streams
- Direct stream URL input in web UI
- Frigate config proxy with auto-discovery via HA Supervisor API
- Frigate connectivity check endpoint
- go2rtc module with auto-discovery
- Network probe system: port scanning, ICMP ping, ARP/OUI lookup, mDNS/HomeKit detection, HTTP probing
- Camera stream tester with automatic JPEG screenshot capture and resolution extraction
- Frigate config generator from camera database
- Web UI pages: search, test, config, URLs, go2rtc streams, HomeKit
- SQLite camera database loaded from external StrixCamDB repository
- Universal Linux installer script with Docker/Compose auto-setup
- In-memory log viewer API endpoint
- Dockerfile with multi-stage build and healthcheck
### Fixed
- Screenshot URL path: removed leading slash
- Credentials with special characters are now URL-encoded in stream URLs
- Credentials no longer leak in debug logs
### Changed
- Version is now injected at build time via ldflags (no hardcoded version in source)
- Pure Go build with no CGO dependency (switched from mattn/go-sqlite3 to modernc.org/sqlite)
- Port is always included in URL for protocols with raw TCP dial
- Structured logging with zerolog, separate from human-readable output
-185
View File
@@ -1,185 +0,0 @@
# Результаты тестирования дедупликации потоков
## Запуск тестов
```bash
go test -v ./internal/camera/stream -run "Dedup|Worst|Multiple"
```
## ✅ Тесты выполнены успешно
Все тесты **PASS**, что означает, что они успешно **ДЕМОНСТРИРУЮТ ПРОБЛЕМУ** текущей системы дедупликации.
---
## 📊 Результаты
### Тест 1: HTTP Authentication Variants
**Проблема:** Один HTTP endpoint генерирует 4 разных URL
```
http://192.168.1.100/snapshot.jpg
http://admin:12345@192.168.1.100/snapshot.jpg
http://192.168.1.100/snapshot.jpg?pwd=12345&user=admin
http://admin:12345@192.168.1.100/snapshot.jpg?pwd=12345&user=admin
```
- **Реально уникальных:** 1 поток
- **Генерируется:** 4 URL
- **Потери:** 3 лишних теста (75%)
---
### Тест 2: HTTP with Placeholders
**Проблема:** URL с плейсхолдерами генерирует дубликаты
```
Entry: snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]
Generated:
http://192.168.1.100/snapshot.cgi?pwd=&user=
http://admin:12345@192.168.1.100/snapshot.cgi?pwd=&user=
http://192.168.1.100/snapshot.cgi?pwd=12345&user=admin
http://admin:12345@192.168.1.100/snapshot.cgi?pwd=12345&user=admin
```
- **Реально уникальных:** 1 поток
- **Генерируется:** 4 URL
- **Потери:** 3 лишних теста (75%)
---
### Тест 3: RTSP with/without Credentials
**Проблема:** RTSP генерирует 2 варианта одного потока
```
rtsp://admin:12345@192.168.1.100/live/main
rtsp://192.168.1.100/live/main
```
- **Реально уникальных:** 1 поток
- **Генерируется:** 2 URL
- **Потери:** 1 лишний тест (50%)
---
### Тест 4: Multiple Sources (Popular + Model)
**Проблема:** Разные источники генерируют одинаковые паттерны
```
Source 1 (Popular Patterns):
rtsp://admin:12345@192.168.1.100/Streaming/Channels/101
rtsp://192.168.1.100/Streaming/Channels/101
Source 2 (Model Patterns):
rtsp://admin:12345@192.168.1.100/Streaming/Channels/101
rtsp://192.168.1.100/Streaming/Channels/101
```
**Текущая дедупликация:**
- Детектирует: 2 точных совпадения (50%)
- НЕ детектирует: 1 семантический дубль
**Итого:**
- Total generated: 4 URL
- After current dedup: 2 URL
- Real unique: 1 поток
- **Эффективность: 50%** (должна быть 75%)
---
### Тест 5: Worst Case Scenario
**Проблема:** Один паттерн из 3 источников (Popular + Model + ONVIF)
```
Popular patterns generates: 4 URLs
Model patterns generates: 4 URLs
ONVIF returns: 1 URL
```
**После текущей дедупликации:** 4 URL остаются
```
http://192.168.1.100/snapshot.jpg
http://admin:12345@192.168.1.100/snapshot.jpg
http://192.168.1.100/snapshot.jpg?pwd=12345&user=admin
http://admin:12345@192.168.1.100/snapshot.jpg?pwd=12345&user=admin
```
**Canonical analysis:**
- Real unique streams: **1**
- URLs being tested: **4**
- **Waste: 3 unnecessary tests (75%)**
- **Time waste: ~6 seconds** (assuming 2s per test)
---
## 🔴 Критические выводы
### 1. Текущая система НЕ работает для семантических дубликатов
Простое сравнение строк `urlMap[url] = true` детектирует только **точные совпадения**.
### 2. Масштаб проблемы
| Сценарий | Генерируется | Реально | Потери |
|----------|--------------|---------|--------|
| HTTP auth variants | 4 | 1 | 75% |
| RTSP with/without creds | 2 | 1 | 50% |
| Multiple sources | 4 | 1 | 75% |
| Worst case | 4 | 1 | 75% |
**Среднее:** ~69% лишних тестов!
### 3. Реальные последствия
При типичном сканировании:
- **Генерируется:** ~190 URL
- **Реально уникальных:** ~80-95
- **Лишних тестов:** 95-110 (50%)
- **Потери времени:** 3-4 минуты
- **Лишняя нагрузка на камеру:** 100+ запросов
- **Плохой UX:** пользователь видит один поток 4 раза
---
## ✅ Решение
Тесты доказывают необходимость **канонической нормализации URL**.
См. файл `/tmp/dedup_solutions.md` для подробного описания решений.
### Рекомендуемый подход: Гибридный
1. **В Builder:** Уменьшить генерацию вариантов (с 4 до 2-3)
2. **В Scanner:** Добавить `CanonicalURL()` функцию
3. **Ожидаемый результат:** Дедупликация 99% вместо текущих 50%
---
## 📝 Следующие шаги
1. ✅ Написать тесты (done)
2. ⏳ Реализовать `normalizer.go` с `CanonicalURL()`
3. ⏳ Модифицировать `Builder.BuildURLsFromEntry()` - убрать лишние варианты
4. ⏳ Модифицировать `Scanner.collectStreams()` - использовать canonical map
5. ⏳ Добавить метрики дедупликации в логи
6. ⏳ Прогнать тесты заново и убедиться в улучшении
---
## 🎯 Ожидаемый результат
После внедрения решения:
```
Real unique streams: 1
URLs being tested: 1 ← вместо 4
Waste: 0 unnecessary tests (0%) ← вместо 75%
Deduplication effectiveness: 99% ← вместо 50%
```
+370
View File
@@ -0,0 +1,370 @@
# Strix for Developers
Strix is a single static binary with embedded web UI and SQLite camera database. No config files, no external dependencies (except optional `ffmpeg` for H264/H265 screenshot conversion). Designed to run alongside your project the same way [go2rtc](https://github.com/AlexxIT/go2rtc) does.
For development and testing without real cameras, use [StrixCamFake](https://github.com/eduard256/StrixCamFake) - IP camera emulator with RTSP, HTTP, RTMP, Bubble and more.
## Binary
Download from [GitHub Releases](https://github.com/eduard256/Strix/releases). Two platforms: `linux/amd64` and `linux/arm64`.
```bash
chmod +x strix-linux-amd64
./strix-linux-amd64
```
The binary needs `cameras.db` in the working directory. Download it from [StrixCamDB](https://github.com/eduard256/StrixCamDB/releases):
```bash
curl -fsSL https://github.com/eduard256/StrixCamDB/releases/latest/download/cameras.db -o cameras.db
./strix-linux-amd64
```
## Docker
```bash
docker run -d --name strix --network host eduard256/strix:latest
```
Database is already embedded in the image.
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `STRIX_LISTEN` | `:4567` | HTTP listen address |
| `STRIX_DB_PATH` | `cameras.db` | Path to SQLite database |
| `STRIX_LOG_LEVEL` | `info` | `trace`, `debug`, `info`, `warn`, `error` |
| `STRIX_FRIGATE_URL` | auto-discovery | Frigate URL, e.g. `http://localhost:5000` |
| `STRIX_GO2RTC_URL` | auto-discovery | go2rtc URL, e.g. `http://localhost:1984` |
## Integration Flow
Typical automation flow using the API:
```
1. Probe device GET /api/probe?ip=192.168.1.100
2. Search database GET /api/search?q=hikvision
3. Build stream URLs GET /api/streams?ids=b:hikvision&ip=192.168.1.100&user=admin&pass=12345
4. Test streams POST /api/test {sources: {streams: [...]}}
5. Poll results GET /api/test?id=xxx
6. Generate config POST /api/generate {mainStream: "rtsp://...", subStream: "rtsp://..."}
```
All endpoints return JSON. CORS is enabled. No authentication.
---
## API Reference
### System
#### `GET /api`
```json
{"version": "2.0.0", "platform": "amd64"}
```
#### `GET /api/health`
```json
{"version": "2.0.0", "uptime": "1h30m0s"}
```
#### `GET /api/log`
Returns in-memory log in `application/jsonlines` format. Passwords are masked automatically.
#### `DELETE /api/log`
Clears in-memory log. Returns `204`.
---
### Search
#### `GET /api/search?q={query}`
Search camera database by brand, model, or preset name. Empty `q` returns all presets + first brands (limit 50).
```bash
curl "localhost:4567/api/search?q=hikvision"
```
```json
{
"results": [
{"type": "brand", "id": "b:hikvision", "name": "Hikvision"},
{"type": "model", "id": "m:hikvision:DS-2CD2032", "name": "Hikvision: DS-2CD2032"}
]
}
```
Result types:
| Type | ID format | Description |
|------|-----------|-------------|
| `preset` | `p:{preset_id}` | Curated URL pattern sets (e.g. "ONVIF", "Popular RTSP") |
| `brand` | `b:{brand_id}` | All URL patterns for a brand |
| `model` | `m:{brand_id}:{model}` | URL patterns for a specific model |
Multi-word queries match independently: `hikvision DS-2CD` matches brand "Hikvision" AND model containing "DS-2CD".
#### `GET /api/streams`
Build full stream URLs from database patterns with credentials and placeholders substituted.
| Param | Required | Description |
|-------|----------|-------------|
| `ids` | yes | Comma-separated IDs from search results |
| `ip` | yes | Camera IP address |
| `user` | no | Username (URL-encoded automatically) |
| `pass` | no | Password (URL-encoded automatically) |
| `channel` | no | Channel number, default `0` |
| `ports` | no | Comma-separated port filter (only return URLs matching these ports) |
```bash
curl "localhost:4567/api/streams?ids=b:hikvision&ip=192.168.1.100&user=admin&pass=12345"
```
```json
{
"streams": [
"rtsp://admin:12345@192.168.1.100/Streaming/Channels/101",
"rtsp://admin:12345@192.168.1.100/Streaming/Channels/102",
"http://admin:12345@192.168.1.100/ISAPI/Streaming/channels/101/picture"
]
}
```
Maximum 20,000 URLs per request. URLs are deduplicated.
---
### Testing
#### `POST /api/test`
Create a test session. 20 parallel workers connect to each URL, extract codecs, capture screenshots.
```bash
curl -X POST localhost:4567/api/test -d '{
"sources": {
"streams": [
"rtsp://admin:12345@192.168.1.100/Streaming/Channels/101",
"rtsp://admin:12345@192.168.1.100/Streaming/Channels/102"
]
}
}'
```
```json
{"session_id": "a1b2c3d4e5f6g7h8"}
```
#### `GET /api/test`
List all active and completed sessions.
```json
{
"sessions": [
{
"session_id": "a1b2c3d4",
"status": "running",
"total": 604,
"tested": 341,
"alive": 191,
"with_screenshot": 191
}
]
}
```
#### `GET /api/test?id={session_id}`
Get session details with full results. Poll this endpoint to track progress.
```json
{
"session_id": "a1b2c3d4",
"status": "done",
"total": 604,
"tested": 604,
"alive": 375,
"with_screenshot": 375,
"results": [
{
"source": "rtsp://admin:***@192.168.1.100/Streaming/Channels/101",
"codecs": ["H264", "PCMA"],
"width": 1920,
"height": 1080,
"latency_ms": 45,
"screenshot": "api/test/screenshot?id=a1b2c3d4&i=0"
}
]
}
```
- `status`: `running` or `done`
- `codecs`: detected media codecs (H264, H265, PCMA, PCMU, OPUS, etc.)
- `width`, `height`: resolution extracted from JPEG screenshot
- `screenshot`: relative URL to fetch the JPEG image
- Sessions expire 30 minutes after completion
#### `DELETE /api/test?id={session_id}`
Cancel a running session and delete it.
```json
{"status": "deleted"}
```
#### `GET /api/test/screenshot?id={session_id}&i={index}`
Returns raw JPEG image. `Content-Type: image/jpeg`.
---
### Config Generation
#### `POST /api/generate`
Generate Frigate config from stream URLs.
```bash
curl -X POST localhost:4567/api/generate -d '{
"mainStream": "rtsp://admin:12345@192.168.1.100/Streaming/Channels/101",
"subStream": "rtsp://admin:12345@192.168.1.100/Streaming/Channels/102",
"name": "front_door",
"objects": ["person", "car"]
}'
```
```json
{
"config": "mqtt:\n enabled: false\n\nrecord:\n enabled: true\n\ngo2rtc:\n streams:\n ...",
"added": [1, 2, 3, 4, 5]
}
```
- `config`: complete Frigate YAML
- `added`: 1-based line numbers of new lines (for highlighting in UI)
**Merge into existing config** - pass `existingConfig` field:
```json
{
"mainStream": "rtsp://...",
"existingConfig": "go2rtc:\n streams:\n existing_cam:\n - rtsp://...\n\ncameras:\n existing_cam:\n ..."
}
```
Strix finds the right insertion points in go2rtc streams and cameras sections. Camera and stream names are deduplicated automatically.
<details>
<summary>Full request schema</summary>
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `mainStream` | string | **yes** | Main stream URL |
| `subStream` | string | no | Sub stream URL for detect role |
| `name` | string | no | Camera name (auto-generated from IP if empty) |
| `existingConfig` | string | no | Existing Frigate YAML to merge into |
| `objects` | string[] | no | Objects to track (default: `["person"]`) |
| `go2rtc` | object | no | `{mainStreamName, subStreamName, mainStreamSource, subStreamSource}` |
| `frigate` | object | no | `{mainStreamPath, subStreamPath, mainStreamInputArgs, subStreamInputArgs}` |
| `detect` | object | no | `{enabled, fps, width, height}` |
| `record` | object | no | `{enabled, retain_days, mode, alerts_days, detections_days, pre_capture, post_capture}` |
| `motion` | object | no | `{enabled, threshold, contour_area}` |
| `snapshots` | object | no | `{enabled}` |
| `audio` | object | no | `{enabled, filters[]}` |
| `ffmpeg` | object | no | `{hwaccel, gpu}` |
| `live` | object | no | `{height, quality}` |
| `birdseye` | object | no | `{enabled, mode}` |
| `onvif` | object | no | `{host, port, user, password, autotracking, required_zones[]}` |
| `ptz` | object | no | `{enabled, presets{}}` |
| `notifications` | object | no | `{enabled}` |
| `ui` | object | no | `{order, dashboard}` |
</details>
---
### Probe
#### `GET /api/probe?ip={ip}`
Probe a network device. Runs 6 checks in parallel within 100ms: port scan, ICMP ping, ARP + OUI vendor lookup, reverse DNS, mDNS/HomeKit query, HTTP probe.
```bash
curl "localhost:4567/api/probe?ip=192.168.1.100"
```
```json
{
"ip": "192.168.1.100",
"reachable": true,
"latency_ms": 2.5,
"type": "standard",
"probes": {
"ping": {"latency_ms": 2.5},
"ports": {"open": [80, 554, 8080]},
"dns": {"hostname": "ipcam.local"},
"arp": {"mac": "C0:56:E3:AA:BB:CC", "vendor": "Hikvision"},
"mdns": null,
"http": {"port": 80, "status_code": 401, "server": "Hikvision-Webs"}
}
}
```
- `type`: `standard`, `homekit`, or `unreachable`
- `ports.open`: scanned from 189 ports known in the camera database
- `arp.vendor`: looked up from OUI table in SQLite database
- HomeKit cameras return `mdns` with `name`, `model`, `category` (`camera` or `doorbell`), `device_id`, `paired`, `port`
- ICMP ping requires `CAP_NET_RAW` capability. Falls back to port scan only.
---
### Frigate
#### `GET /api/frigate/config`
Get current Frigate config. Frigate is discovered automatically by probing known addresses (`localhost:5000`, `ccab4aaf-frigate:5000`) or via `STRIX_FRIGATE_URL`.
```json
{"connected": true, "url": "http://localhost:5000", "config": "mqtt:\n enabled: false\n ..."}
```
```json
{"connected": false, "config": ""}
```
#### `POST /api/frigate/config/save?save_option={option}`
Save config to Frigate. Request body is plain text (YAML config).
| Option | Description |
|--------|-------------|
| `saveonly` | Save config without restart (default) |
| `restart` | Save config and restart Frigate |
---
### go2rtc
#### `PUT /api/go2rtc/streams?name={name}&src={source}`
Add a stream to go2rtc. Proxied to local go2rtc instance (discovered automatically or via `STRIX_GO2RTC_URL`).
```bash
curl -X PUT "localhost:4567/api/go2rtc/streams?name=front_door&src=rtsp://admin:12345@192.168.1.100/Streaming/Channels/101"
```
```json
{"success": true}
```
```json
{"success": false, "error": "go2rtc not found"}
```
-164
View File
@@ -1,164 +0,0 @@
# 🐳 Docker Setup for Strix
## Quick Start
### Using Docker Compose (Recommended)
```bash
# Start Strix
docker-compose up -d
# View logs
docker-compose logs -f strix
# Stop Strix
docker-compose down
```
Access: http://localhost:4567
### Using Docker Run
```bash
docker run -d \
--name strix \
-p 4567:4567 \
eduard256/strix:latest
```
## Configuration
### Using Environment Variables
```bash
docker run -d \
--name strix \
-p 8080:8080 \
-e STRIX_API_LISTEN=:8080 \
-e STRIX_LOG_LEVEL=debug \
eduard256/strix:latest
```
### Using Config File
```bash
# Create strix.yaml
cat > strix.yaml <<EOF
api:
listen: ":8080"
EOF
# Run with mounted config
docker run -d \
--name strix \
-p 8080:8080 \
-v $(pwd)/strix.yaml:/app/strix.yaml:ro \
eduard256/strix:latest
```
## Full Stack (Strix + go2rtc + Frigate)
```bash
docker-compose -f docker-compose.full.yml up -d
```
Services:
- Strix: http://localhost:4567
- go2rtc: http://localhost:1984
- Frigate: http://localhost:5000
## Building Locally
```bash
# Build for your platform
docker build -t strix:local .
# Build for multiple platforms
docker buildx build --platform linux/amd64,linux/arm64 -t strix:multi .
```
## Image Information
- **Image**: `eduard256/strix:latest`
- **Platforms**: linux/amd64, linux/arm64
- **Size**: ~80-90MB
- **Base**: Alpine Linux
- **User**: Non-root (strix:1000)
## Included Dependencies
- ffmpeg/ffprobe (stream validation)
- ca-certificates (HTTPS support)
- tzdata (timezone support)
- wget (healthcheck)
- Camera database (3600+ models)
## Health Check
```bash
# Check container health
docker inspect --format='{{.State.Health.Status}}' strix
# Manual health check
docker exec strix wget -q -O- http://localhost:4567/api/v1/health
```
## Troubleshooting
### View logs
```bash
docker logs strix
docker logs -f strix # Follow logs
```
### Check if ffprobe works
```bash
docker exec strix ffprobe -version
```
### Inspect container
```bash
docker exec -it strix sh
```
### Restart container
```bash
docker restart strix
```
## Security
- Runs as non-root user (UID 1000)
- Minimal attack surface (Alpine base)
- No unnecessary packages
- Health checks enabled
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `STRIX_API_LISTEN` | `:4567` | Server listen address |
| `STRIX_LOG_LEVEL` | `info` | Log level (debug, info, warn, error) |
| `STRIX_LOG_FORMAT` | `json` | Log format (json, text) |
| `STRIX_DATA_PATH` | `./data` | Camera database path |
## Volumes
```bash
# Optional: Custom configuration
-v ./strix.yaml:/app/strix.yaml:ro
# Optional: Custom camera database
-v ./data:/app/data:ro
```
## Docker Hub
Pre-built images available at: https://hub.docker.com/r/eduard256/strix
Tags:
- `latest` - Latest stable release
- `v0.1.0` - Specific version
- `0.1` - Minor version
- `0` - Major version
- `main` - Development branch
+11 -52
View File
@@ -1,67 +1,26 @@
# Strix - Smart IP Camera Stream Discovery System FROM golang:1.26-alpine AS builder
# Multi-stage Dockerfile for minimal image size
# Stage 1: Builder WORKDIR /src
FROM golang:1.24-alpine AS builder
WORKDIR /build
# Install build dependencies
RUN apk add --no-cache git
# Copy go mod files
COPY go.mod go.sum ./ COPY go.mod go.sum ./
RUN go mod download RUN go mod download
# Copy source code
COPY . . COPY . .
# Build static binary ARG VERSION=dev
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} go build \ RUN CGO_ENABLED=0 go build -ldflags "-s -w -X main.version=${VERSION}" -o /strix .
-ldflags="-s -w -X main.Version=docker" \
-o strix \
cmd/strix/main.go
# Stage 2: Runtime
FROM alpine:latest FROM alpine:latest
# Install runtime dependencies RUN apk add --no-cache ffmpeg ca-certificates
# - ffmpeg/ffprobe: Required for RTSP stream validation
# - ca-certificates: Required for HTTPS requests to cameras COPY --from=builder /strix /usr/local/bin/strix
# - tzdata: Required for correct timestamps
# - wget: Required for healthcheck
RUN apk add --no-cache \
ffmpeg \
ca-certificates \
tzdata \
wget \
&& rm -rf /var/cache/apk/*
WORKDIR /app WORKDIR /app
COPY cameras.db .
# Copy binary from builder
COPY --from=builder /build/strix .
# Copy camera database (CRITICAL - app won't work without it)
COPY --from=builder /build/data ./data
# Create directory for optional config
RUN mkdir -p /app/config
# Create non-root user for security
RUN addgroup -g 1000 strix && \
adduser -D -u 1000 -G strix strix && \
chown -R strix:strix /app
# Switch to non-root user
USER strix
# Expose default port
EXPOSE 4567 EXPOSE 4567
# Health check HEALTHCHECK --interval=30s --timeout=3s CMD wget -q --spider http://localhost:4567/api/health || exit 1
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:4567/api/v1/health || exit 1
# Start application USER nobody
CMD ["./strix"] ENTRYPOINT ["strix"]
-155
View File
@@ -1,155 +0,0 @@
# Frigate Configuration - Запись по движению с детекцией объектов
Конфигурация для Frigate с записью при обнаружении движения и детекцией объектов (person, car, cat, dog).
## Dual-Stream конфиг (Main + Sub) - РЕКОМЕНДУЕТСЯ
Используется sub stream для детекции (экономия CPU), main stream для записи (качество).
```yaml
mqtt:
enabled: false
# Глобальные настройки записи
record:
enabled: true
retain:
days: 7
mode: motion # Записывать только при движении
# Go2RTC Configuration (Frigate built-in)
go2rtc:
streams:
'10_0_20_112_main':
- rtsp://admin:password@10.0.20.112/live/main
'10_0_20_112_sub':
- rtsp://admin:password@10.0.20.112/live/sub
# Frigate Camera Configuration
cameras:
camera_10_0_20_112:
ffmpeg:
inputs:
- path: rtsp://127.0.0.1:8554/10_0_20_112_sub
input_args: preset-rtsp-restream
roles:
- detect
- path: rtsp://127.0.0.1:8554/10_0_20_112_main
input_args: preset-rtsp-restream
roles:
- record
live:
streams:
Main Stream: 10_0_20_112_main # HD для просмотра
Sub Stream: 10_0_20_112_sub # Низкое разрешение (опционально)
objects:
track:
- person
- car
- cat
- dog
record:
enabled: true
version: 0.16-0
```
## Single-Stream конфиг (Main только)
Когда нет sub stream - используется main для детекции и записи.
```yaml
mqtt:
enabled: false
# Глобальные настройки записи
record:
enabled: true
retain:
days: 7
mode: motion # Записывать только при движении
# Go2RTC Configuration (Frigate built-in)
go2rtc:
streams:
'10_0_20_112_main':
- rtsp://admin:password@10.0.20.112/stream1
# Frigate Camera Configuration
cameras:
camera_10_0_20_112:
ffmpeg:
inputs:
- path: rtsp://127.0.0.1:8554/10_0_20_112_main
input_args: preset-rtsp-restream
roles:
- detect
- record
objects:
track:
- person
- car
- cat
- dog
record:
enabled: true
version: 0.16-0
```
## Режимы записи
### `mode: motion` (рекомендуется)
Записывает видео при обнаружении движения. Экономит место на диске.
### `mode: active_objects`
Записывает только когда обнаружены объекты (person, car, etc). Еще больше экономия.
### `mode: all`
Записывает постоянно 24/7. Требует много места на диске.
## Преимущества Dual-Stream подхода
**Низкая нагрузка на CPU** - детекция на sub stream (обычно 352x288 или 640x480)
**Качественная запись** - запись на main stream в полном разрешении (HD/4K)
**Быстрая детекция** - меньше пикселей = быстрее обработка
**Авто-определение разрешения** - Frigate сам определяет параметры потока
**Одно подключение к камере** - Go2RTC мультиплексирует потоки
## Что делает этот конфиг
**Детекция** - работает постоянно, ищет объекты
**Запись** - начинается при движении
**Объекты** - распознает person, car, cat, dog
**Хранение** - 7 дней записи
**Snapshots** - сохраняются автоматически при детекции
## Добавление других объектов
Чтобы добавить больше объектов для детекции, измените секцию `objects.track`:
```yaml
objects:
track:
- person
- car
- cat
- dog
- motorcycle # Мотоциклы
- bicycle # Велосипеды
- truck # Грузовики
- bus # Автобусы
```
Полный список доступных объектов: https://docs.frigate.video/configuration/objects/
## Примечания
- Dual-stream экономит CPU, используйте когда камера поддерживает sub stream
- Single-stream проще, но требует больше CPU для детекции (особенно на 4K)
- Frigate автоматически определяет разрешение потоков, блок `detect` не нужен
- Запись по движению экономит место, но может пропустить начало события
- Для непрерывной записи используйте `mode: all`
- Frigate автоматически управляет удалением старых записей
- Main stream поддерживает любое разрешение: HD (1920x1080), 4K (3840x2160) и выше
-147
View File
@@ -1,147 +0,0 @@
.PHONY: all build clean run test install deps fmt vet lint
# Variables
BINARY_NAME=strix
BINARY_PATH=bin/$(BINARY_NAME)
MAIN_PATH=cmd/strix/main.go
GO=go
GOFLAGS=-v
LDFLAGS=-ldflags "-s -w -X main.Version=$$(git describe --tags --always --dirty 2>/dev/null || echo 'dev')"
# Default target
all: build
# Build the application
build:
@echo "Building $(BINARY_NAME)..."
@mkdir -p bin
$(GO) build $(GOFLAGS) $(LDFLAGS) -o $(BINARY_PATH) $(MAIN_PATH)
@echo "Build complete: $(BINARY_PATH)"
# Run the application
run: build
@echo "Running $(BINARY_NAME)..."
./$(BINARY_PATH)
# Clean build artifacts
clean:
@echo "Cleaning..."
@rm -rf bin/
@$(GO) clean
@echo "Clean complete"
# Install dependencies
deps:
@echo "Installing dependencies..."
$(GO) mod download
$(GO) mod tidy
@echo "Dependencies installed"
# Format code
fmt:
@echo "Formatting code..."
$(GO) fmt ./...
@echo "Code formatted"
# Run vet
vet:
@echo "Running go vet..."
$(GO) vet ./...
@echo "Vet complete"
# Run linter (requires golangci-lint)
lint:
@echo "Running linter..."
@if command -v golangci-lint > /dev/null; then \
golangci-lint run ./...; \
else \
echo "golangci-lint not installed, skipping..."; \
fi
# Run tests
test:
@echo "Running tests..."
$(GO) test -v -race -cover ./...
@echo "Tests complete"
# Run tests with coverage
test-coverage:
@echo "Running tests with coverage..."
$(GO) test -v -race -coverprofile=coverage.out ./...
$(GO) tool cover -html=coverage.out -o coverage.html
@echo "Coverage report generated: coverage.html"
# Build for multiple platforms
build-all:
@echo "Building for multiple platforms..."
@mkdir -p bin
@echo "Building for Linux amd64..."
GOOS=linux GOARCH=amd64 $(GO) build $(GOFLAGS) $(LDFLAGS) -o bin/$(BINARY_NAME)-linux-amd64 $(MAIN_PATH)
@echo "Building for Linux arm64..."
GOOS=linux GOARCH=arm64 $(GO) build $(GOFLAGS) $(LDFLAGS) -o bin/$(BINARY_NAME)-linux-arm64 $(MAIN_PATH)
@echo "Building for Darwin amd64..."
GOOS=darwin GOARCH=amd64 $(GO) build $(GOFLAGS) $(LDFLAGS) -o bin/$(BINARY_NAME)-darwin-amd64 $(MAIN_PATH)
@echo "Building for Darwin arm64..."
GOOS=darwin GOARCH=arm64 $(GO) build $(GOFLAGS) $(LDFLAGS) -o bin/$(BINARY_NAME)-darwin-arm64 $(MAIN_PATH)
@echo "Building for Windows amd64..."
GOOS=windows GOARCH=amd64 $(GO) build $(GOFLAGS) $(LDFLAGS) -o bin/$(BINARY_NAME)-windows-amd64.exe $(MAIN_PATH)
@echo "Multi-platform build complete"
# Install the binary to GOPATH
install: build
@echo "Installing $(BINARY_NAME)..."
$(GO) install $(GOFLAGS) $(LDFLAGS) $(MAIN_PATH)
@echo "Installation complete"
# Development mode with live reload (requires air)
dev:
@if command -v air > /dev/null; then \
air; \
else \
echo "Air not installed. Install with: go install github.com/air-verse/air@latest"; \
echo "Running without live reload..."; \
$(MAKE) run; \
fi
# Docker build
docker-build:
@echo "Building Docker image..."
docker build -t strix:latest .
@echo "Docker image built: strix:latest"
# Docker run
docker-run:
@echo "Running Docker container..."
docker run -p 8080:8080 -v $(PWD)/data:/data strix:latest
# Check code quality
check: fmt vet lint test
@echo "Code quality check complete"
# Help
help:
@echo "Strix - Smart IP Camera Stream Discovery System"
@echo ""
@echo "Available targets:"
@echo " make build - Build the application"
@echo " make run - Build and run the application"
@echo " make clean - Remove build artifacts"
@echo " make deps - Install dependencies"
@echo " make fmt - Format code"
@echo " make vet - Run go vet"
@echo " make lint - Run linter"
@echo " make test - Run tests"
@echo " make test-coverage - Run tests with coverage"
@echo " make build-all - Build for multiple platforms"
@echo " make install - Install to GOPATH"
@echo " make dev - Run in development mode with live reload"
@echo " make docker-build - Build Docker image"
@echo " make docker-run - Run Docker container"
@echo " make check - Run all quality checks"
@echo " make help - Show this help message"
+149 -504
View File
@@ -1,556 +1,201 @@
# Strix <h1 align="center">
[![GitHub Stars](https://img.shields.io/github/stars/eduard256/strix?style=social)](https://github.com/eduard256/strix/stargazers) <a href="https://github.com/eduard256/Strix">
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) <img src="https://github.com/eduard256/Strix/releases/download/v2.0.0/icon-192.png" width="64" alt="Strix" valign="middle">
[![Docker Pulls](https://img.shields.io/docker/pulls/eduard256/strix)](https://hub.docker.com/r/eduard256/strix) </a>
&nbsp;|&nbsp;
STRIX
</h1>
<p align="center">
<a href="https://github.com/eduard256/strix/stargazers"><img src="https://img.shields.io/github/stars/eduard256/strix?style=flat-square&logo=github" alt="GitHub Stars"></a>
<a href="https://hub.docker.com/r/eduard256/strix"><img src="https://img.shields.io/docker/pulls/eduard256/strix?style=flat-square&logo=docker&logoColor=white&label=pulls" alt="Docker Pulls"></a>
<a href="https://github.com/eduard256/Strix/releases"><img src="https://img.shields.io/github/downloads/eduard256/Strix/total?color=blue&style=flat-square&logo=github" alt="GitHub Downloads"></a>
<a href="https://github.com/eduard256/Strix/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square" alt="License"></a>
</p>
## Spent 2 years googling URL for your Chinese camera? Camera stream discovery and Frigate config generator.
**Strix finds working streams automatically. In 30 seconds.** - 3,600+ camera brands with 100,000+ [URL patterns](#streams) in SQLite database
- automatic device [probing](#probe) in 100ms: ports, ARP/OUI, mDNS/HomeKit, HTTP
- **67,288** camera models - 20 parallel workers [test every URL](#testing) with live screenshots
- **3,636** brands (from Hikvision to AliExpress no-name) - supports [RTSP, HTTP, RTMP, Bubble, DVRIP](#supported-protocols) and more
- **102,787** URL patterns (RTSP, HTTP, MJPEG, JPEG, BUBBLE) - ready [Frigate config](#config-generation) with smart merge into existing setup
- auto-discovery of Frigate and [go2rtc](https://github.com/AlexxIT/go2rtc) on local network
![Demo](assets/main.gif) - zero-dependency static [binary](#binary) for Linux amd64/arm64
- can be used as [standalone app](#binary), [Docker](#docker), or [Home Assistant add-on](#home-assistant-add-on)
--- ---
## Your Problem? <a href="https://youtu.be/JgVWsl4NApE">
<img src="https://github.com/eduard256/Strix/releases/download/v2.0.0/demo.gif" width="100%">
</a>
- ❌ Bought ZOSI NVR, zero documentation <p align="center">
- ❌ Camera has no RTSP, only weird JPEG snapshots <a href="https://gostrix.github.io/demo.html"><b>Live Demo</b></a>
- ❌ Frigate eating 70% CPU &nbsp;&bull;&nbsp;
- ❌ Config breaks after adding each camera <a href="https://gostrix.github.io/"><b>Supported Cameras</b></a>
- ❌ Don't understand Frigate syntax &nbsp;&bull;&nbsp;
<a href="https://youtu.be/JgVWsl4NApE"><b>Video</b></a>
&nbsp;&bull;&nbsp;
<a href="DEVELOPERS.md"><b>API Docs</b></a>
</p>
## Solution ## Install
-**Auto-discovery** - tests 102,787 URL variations in parallel Any Linux or Proxmox, one command:
-**Any protocol** - No RTSP? Finds HTTP MJPEG
-**Config generation** - ready Frigate.yml in 2 minutes
-**Sub/Main streams** - CPU from 30% → 8%
-**Smart merging** - adds camera to existing config with 500+ cameras
---
## 🚀 Installation (One Command)
### Ubuntu / Debian
```bash ```bash
sudo apt update && command -v docker >/dev/null 2>&1 || curl -fsSL https://get.docker.com | sudo sh && docker run -d --name strix -p 4567:4567 --restart unless-stopped eduard256/strix:latest bash <(curl -fsSL https://raw.githubusercontent.com/eduard256/Strix/main/install.sh)
``` ```
Open **http://YOUR_SERVER_IP:4567** Run as root (or with `sudo`). Interactive installer detects your system (Linux / Proxmox) and guides you through setup.
Open `http://YOUR_IP:4567`
## How it works
<a id="probe"></a>
Enter camera IP. Strix probes the device - open ports, MAC vendor, mDNS, HTTP server.
![](https://github.com/eduard256/Strix/releases/download/v2.0.0/01-enter-ip.png)
<a id="search"></a>
Search camera model in database. Enter credentials if needed.
![](https://github.com/eduard256/Strix/releases/download/v2.0.0/02-camera-config.png)
<a id="streams"></a>
Strix builds all possible stream URLs from database patterns.
![](https://github.com/eduard256/Strix/releases/download/v2.0.0/03-stream-urls.png)
<a id="testing"></a>
20 parallel workers test every URL. Live screenshots, codecs, resolution, latency.
![](https://github.com/eduard256/Strix/releases/download/v2.0.0/04-testing.png)
Pick main and sub streams from results.
![](https://github.com/eduard256/Strix/releases/download/v2.0.0/05-results.png)
<a id="config-generation"></a>
Generate ready Frigate config. Copy, download, or save directly to Frigate.
![](https://github.com/eduard256/Strix/releases/download/v2.0.0/06-frigate-config.png)
Camera works in Frigate. Done.
![](https://github.com/eduard256/Strix/releases/download/v2.0.0/07-frigate-result.png)
## Other install methods
### Docker
```bash
docker run -d --name strix --network host --restart unless-stopped eduard256/strix:latest
```
### Docker Compose ### Docker Compose
```bash Strix only:
sudo apt update && command -v docker >/dev/null 2>&1 || curl -fsSL https://get.docker.com | sudo sh && command -v docker-compose >/dev/null 2>&1 || { sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && sudo chmod +x /usr/local/bin/docker-compose; } && curl -fsSL https://raw.githubusercontent.com/eduard256/Strix/main/docker-compose.yml -o docker-compose.yml && docker-compose up -d
```
### Home Assistant Add-on (Beta)
⚠️ **Status:** Experimental (SSE has bugs, Docker recommended)
**Installation:**
1. Go to **Settings****Add-ons****Add-on Store**
2. Click **⋮** (top right) → **Repositories**
3. Add: `https://github.com/eduard256/hassio-strix`
4. Find **"Strix"** in store
5. Click **Install**
6. Enable **"Start on boot"** and **"Show in sidebar"**
7. Click **Start**
**Known Issues:**
- Real-time progress may not display (Ingress SSE limitation)
- Use Docker installation for better experience
---
## How to Use
### Step 1: Open Web Interface
```
http://YOUR_SERVER_IP:4567
```
### Step 2: Enter Camera Details
- **IP Address**: `192.168.1.100`
- **Username**: `admin` (if required)
- **Password**: your camera password
- **Model**: optional, improves accuracy
### Step 3: Discover Streams
Click **"Discover Streams"**
Watch real-time progress:
- Which URL is being tested
- How many tested
- Found streams appear instantly
Wait 30-60 seconds.
### Step 4: Choose Stream
Strix shows details for each stream:
| Stream | Details |
|--------|---------|
| **Protocol** | RTSP, HTTP, MJPEG, JPEG |
| **Resolution** | 1920x1080, 640x480 |
| **FPS** | 25, 15, 10 |
| **Codec** | H264, H265, MJPEG |
| **Audio** | Yes / No |
### Step 5: Generate Frigate Config
Click **"Use Stream"** → **"Generate Frigate Config"**
You get ready config:
```yaml
go2rtc:
streams:
'192_168_1_100_main':
- http://admin:pass@192.168.1.100:8000/video.mjpg
'192_168_1_100_sub':
- http://admin:pass@192.168.1.100:8000/video2.mjpg
cameras:
camera_192_168_1_100:
ffmpeg:
inputs:
- path: rtsp://127.0.0.1:8554/192_168_1_100_sub
roles: [detect] # CPU 8% instead of 70%
- path: rtsp://127.0.0.1:8554/192_168_1_100_main
roles: [record] # HD recording
objects:
track: [person, car, cat, dog]
record:
enabled: true
```
**Smart Merging:**
- Paste your existing `frigate.yml` with 500 cameras
- Strix adds camera #501 correctly
- Doesn't break structure
- Preserves all settings
### Step 6: Add to Frigate
Copy config → Paste to `frigate.yml` → Restart Frigate
**Done!**
---
## Features
### Exotic Camera Support
90% of Chinese cameras don't have RTSP. Strix supports everything:
- **HTTP MJPEG** - most old cameras
- **JPEG snapshots** - auto-converted to stream via FFmpeg
- **RTSP** - if available
- **HTTP-FLV** - some Chinese brands
- **BUBBLE** - proprietary Chinese NVR/DVR protocol
- **ONVIF** - auto-discovery
### Camera Database
**67,288 models from 3,636 brands:**
- **Known brands**: Hikvision, Dahua, Axis, Foscam, TP-Link
- **Chinese no-names**: ZOSI, Escam, Sricam, Wanscam, Besder
- **AliExpress junk**: cameras without name, OEM models
- **Old systems**: NVR/DVR with proprietary protocols
### Discovery Methods
Strix tries all methods in parallel:
**1. ONVIF** (30% success rate)
- Asks camera directly for stream URLs
- Works for ONVIF-compatible cameras
**2. Database Lookup** (60% success rate)
- 67,288 models with known working URLs
- Brand and model-specific patterns
**3. Popular Patterns** (90% success rate)
- 206 most common URL paths
- Works even for unknown cameras
**Result: Finds stream for 95% of cameras**
### Frigate Config Generation
**What you get:**
**Main/Sub streams**
- Main (HD) for recording
- Sub (low res) for object detection
- CPU usage reduced 5-10x
**Ready go2rtc config**
- Stream multiplexing
- Protocol conversion
- JPEG → RTSP via FFmpeg
**Smart config merging**
- Add to existing config
- Preserve structure
- No manual YAML editing
**Pre-configured detection**
- person, car, cat, dog
- Ready motion recording
- 7 days retention
### Speed
- Tests **20 URLs in parallel**
- Average discovery time: **30-60 seconds**
- Complex cameras: **2-3 minutes**
- Real-time progress updates via SSE
---
## Advanced Configuration
### Docker Environment Variables
```yaml
environment:
- STRIX_API_LISTEN=:8080 # Custom port
- STRIX_LOG_LEVEL=debug # Detailed logs
- STRIX_LOG_FORMAT=json # JSON logging
```
### Config File
Create `strix.yaml`:
```yaml
api:
listen: ":8080"
```
Example: [strix.yaml.example](strix.yaml.example)
### Discovery Parameters
In web UI under **Advanced**:
- **Channel** - for NVR systems (usually 0)
- **Timeout** - max discovery time (default: 240s)
- **Max Streams** - stop after N streams (default: 10)
---
## FAQ
### No streams found?
**Check network:**
```bash
ping 192.168.1.100
```
Camera must be reachable.
**Verify credentials:**
- Username/password correct?
- Try without credentials (some cameras are open)
**Try without model:**
- Strix will run ONVIF + 206 popular patterns
- Works for cameras not in database
### Camera not in database?
**No problem.**
Strix will still find stream via:
1. ONVIF (if supported)
2. 206 popular URL patterns
3. Common ports and paths
4. HTTP MJPEG on various ports
5. JPEG snapshot endpoints
**Help the project:**
- Found working stream? [Create Issue](https://github.com/eduard256/Strix/issues)
- Share model and URL
- We'll add to database
### Found only JPEG snapshots?
**Normal for old cameras.**
Strix auto-converts JPEG to stream via FFmpeg:
```yaml
go2rtc:
streams:
camera_main:
- exec:ffmpeg -loop 1 -framerate 10 -i http://192.168.1.100/snapshot.jpg -c:v libx264 -f rtsp {output}
```
Frigate gets normal 10 FPS stream.
### Stream found but doesn't work in Frigate?
**Try another stream:**
- Strix usually finds 3-10 variants
- Some may need special FFmpeg parameters
**Use sub stream:**
- For object detection
- Less CPU load
- Better performance
### How does config generation work?
**For new config:**
- Strix creates complete `frigate.yml` from scratch
- Includes go2rtc, camera, object detection
**For existing config:**
- Paste your current `frigate.yml`
- Strix adds new camera
- Preserves all existing cameras
- Doesn't break structure
**Main/Sub streams:**
- Main (HD) - for recording
- Sub (low res) - for detection
- CPU savings 5-10x
### Is it safe to enter passwords?
**Yes.**
- Strix runs locally on your network
- Nothing sent to external servers
- Passwords not saved
- Open source - check the code yourself
### Works offline?
**Yes.**
- Database embedded in Docker image
- Internet only needed to download image
- Runs offline after that
---
## API Reference
REST API available for automation:
### Health Check
```bash ```bash
GET /api/v1/health curl -O https://raw.githubusercontent.com/eduard256/Strix/main/docker-compose.yml
docker compose up -d
``` ```
### Search Cameras Strix + [Frigate](https://github.com/blakeblackshear/frigate):
```bash ```bash
POST /api/v1/cameras/search curl -O https://raw.githubusercontent.com/eduard256/Strix/main/docker-compose.frigate.yml
docker compose -f docker-compose.frigate.yml up -d
{
"query": "hikvision",
"limit": 10
}
``` ```
### Discover Streams (SSE) Strix + [go2rtc](https://github.com/AlexxIT/go2rtc):
```bash ```bash
POST /api/v1/streams/discover curl -O https://raw.githubusercontent.com/eduard256/Strix/main/docker-compose.go2rtc.yml
docker compose -f docker-compose.go2rtc.yml up -d
{
"target": "192.168.1.100",
"username": "admin",
"password": "12345",
"model": "DS-2CD2xxx",
"timeout": 240,
"max_streams": 10
}
``` ```
Returns Server-Sent Events with real-time progress. ### Podman
**Full API documentation:** [DOCKER.md](DOCKER.md) Podman drops `NET_RAW` and `NET_ADMIN` by default, which Strix needs for network scanning. Add them explicitly:
---
## Technical Details
### Architecture
- **Language:** Go 1.24
- **Database:** 3,636 JSON files
- **Image size:** 80-90 MB (Alpine Linux)
- **Dependencies:** FFmpeg/FFprobe for validation
- **Concurrency:** Worker pool (20 parallel tests)
- **Real-time:** Server-Sent Events (SSE)
### Build from Source
```bash ```bash
git clone https://github.com/eduard256/Strix podman run -d \
cd Strix --name strix \
make build --network host \
./bin/strix --cap-add=NET_RAW \
--cap-add=NET_ADMIN \
--restart unless-stopped \
eduard256/strix:latest
``` ```
**Requirements:** Or run with `--privileged` if you prefer.
- Go 1.21+
- FFprobe (optional, for stream validation)
### Docker Platforms ### Home Assistant Add-on
- linux/amd64 1. **Settings** > **Add-ons** > **Add-on Store**
- linux/arm64 2. Menu (top right) > **Repositories** > add `https://github.com/eduard256/hassio-strix`
3. Install **Strix**, enable **Start on boot** and **Show in sidebar**
Auto-built and published to Docker Hub on every push to `main`. ### Umbrel
--- <a href="https://apps.umbrel.com/app/strix">
<img src="https://apps.umbrel.com/api/app/strix/badge-light.svg" alt="Install on Umbrel" height="60">
</a>
## Use Cases Install in one click from the [Umbrel App Store](https://apps.umbrel.com/app/strix).
### Home Automation ### Binary
- Add cheap cameras to Home Assistant Download from [GitHub Releases](https://github.com/eduard256/Strix/releases). No dependencies except `ffmpeg` for screenshot conversion.
- Integrate with Frigate NVR
- Object detection with low CPU
- Motion recording
### Security Systems ```bash
chmod +x strix-linux-amd64
- Discover streams in old NVR systems STRIX_LISTEN=:4567 ./strix-linux-amd64
- Find backup cameras without docs
- Migrate from proprietary DVR to Frigate
- Reduce hardware requirements
### IP Camera Testing
- Test cameras before deployment
- Verify stream quality
- Find optimal resolution/FPS
- Check codec compatibility
---
## Troubleshooting
### Frigate still eating CPU?
**Use sub stream:**
1. Find both main and sub streams with Strix
2. Generate config with both
3. Sub for detect, main for record
4. CPU drops 5-10x
**Example:**
```yaml
inputs:
- path: rtsp://127.0.0.1:8554/camera_sub # 640x480 for detect
roles: [detect]
- path: rtsp://127.0.0.1:8554/camera_main # 1920x1080 for record
roles: [record]
``` ```
### Can't find specific stream quality? ## Supported protocols
**In web UI:** | Protocol | Port | Description |
- Strix shows all found streams |----------|------|-------------|
- Filter by resolution | RTSP | 554 | Most IP cameras |
- Choose optimal FPS | RTSPS | 322 | RTSP over TLS |
- Select codec (H264 recommended for Frigate) | HTTP/HTTPS | 80/443 | MJPEG, JPEG snapshots, HLS, MPEG-TS |
| RTMP | 1935 | Some Chinese NVRs |
| Bubble | 80 | XMeye/NetSurveillance cameras |
| DVRIP | 34567 | Sofia protocol DVR/NVR |
| HomeKit | 51826 | Apple HomeKit cameras via HAP |
### Stream works but no audio in Frigate? ## Configuration
**Check Strix stream details:** | Variable | Default | Description |
- "Has Audio" field shows if audio present |----------|---------|-------------|
- Some cameras have video-only streams | `STRIX_LISTEN` | `:4567` | HTTP listen address |
- Try different stream URL from Strix results | `STRIX_DB_PATH` | `cameras.db` | Path to SQLite camera database |
| `STRIX_LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error`, `trace` |
| `STRIX_FRIGATE_URL` | auto-discovery | Frigate URL, e.g. `http://localhost:5000` |
| `STRIX_GO2RTC_URL` | auto-discovery | go2rtc URL, e.g. `http://localhost:1984` |
### Discovery takes too long? ## Camera database
**Reduce search scope:** SQLite database with 3,600+ brands and 100,000+ URL patterns. Maintained separately in [StrixCamDB](https://github.com/eduard256/StrixCamDB). Database is embedded in Docker image and bundled with binary releases.
- Specify exact camera model (faster database lookup)
- Lower "Max Streams" (stops after N found)
- Reduce timeout (default 240s)
**In Advanced settings:** [Browse supported cameras](https://gostrix.github.io/) - search by brand or model to check if your camera is in the database.
```
Max Streams: 5 (instead of 10)
Timeout: 120 (instead of 240)
```
--- Three entity types:
- **Presets** - curated sets of popular URL patterns (e.g. "ONVIF", "Popular RTSP")
- **Brands** - all URL patterns for a brand (e.g. "Hikvision", "Dahua")
- **Models** - URL patterns for a specific model within a brand
## Contributing Camera not in the database? [Add it here](https://gostrix.github.io/#/contribute).
### Add Your Camera **Developers:** integrate [Strix HTTP API](DEVELOPERS.md) into your smart home platform.
Found working stream for camera not in database? **Testing:** [StrixCamFake](https://github.com/eduard256/StrixCamFake) - IP camera emulator for development and testing. [StrixAHKCamFake](https://github.com/eduard256/StrixAHKCamFake) - Apple HomeKit camera emulator.
1. [Create Issue](https://github.com/eduard256/Strix/issues)
2. Provide:
- Camera brand and model
- Working URL pattern
- Protocol (RTSP/HTTP/etc)
3. We'll add to database
### Report Bugs
- [GitHub Issues](https://github.com/eduard256/Strix/issues)
- Include logs (set `STRIX_LOG_LEVEL=debug`)
- Camera model and IP (if possible)
### Feature Requests
- [GitHub Discussions](https://github.com/eduard256/Strix/discussions)
- Describe use case
- Explain expected behavior
---
## Credits
- **Camera database:** [ispyconnect.com](https://www.ispyconnect.com)
- **Inspiration:** [go2rtc](https://github.com/AlexxIT/go2rtc) by AlexxIT
- **Community:** Home Assistant, Frigate NVR users
---
## License
MIT License - use commercially, modify, distribute freely.
See [LICENSE](LICENSE) file for details.
---
## Support
- **Issues:** [GitHub Issues](https://github.com/eduard256/Strix/issues)
- **Discussions:** [GitHub Discussions](https://github.com/eduard256/Strix/discussions)
- **Docker:** [Docker Hub](https://hub.docker.com/r/eduard256/strix)
---
**Made for people tired of cameras without documentation**
*Tested on Chinese AliExpress junk that finally works now.*
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

-202
View File
@@ -1,202 +0,0 @@
package main
import (
"context"
"fmt"
"log/slog"
"net"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/eduard256/Strix/internal/api"
"github.com/eduard256/Strix/internal/config"
"github.com/eduard256/Strix/internal/utils/logger"
"github.com/eduard256/Strix/webui"
"github.com/go-chi/chi/v5"
)
const (
// Version is the application version
Version = "1.0.4"
// Banner is the application banner
Banner = `
███████╗████████╗██████╗ ██╗██╗ ██╗
██╔════╝╚══██╔══╝██╔══██╗██║╚██╗██╔╝
███████╗ ██║ ██████╔╝██║ ╚███╔╝
╚════██║ ██║ ██╔══██╗██║ ██╔██╗
███████║ ██║ ██║ ██║██║██╔╝ ██╗
╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝
Smart IP Camera Stream Discovery System
Version: %s
`
)
func main() {
// Print banner
fmt.Printf(Banner, Version)
fmt.Println()
// Load configuration
cfg := config.Load()
// Setup logger
slogger := cfg.SetupLogger()
slog.SetDefault(slogger)
// Create adapter for our interface
log := logger.NewAdapter(slogger)
log.Info("starting Strix",
slog.String("version", Version),
slog.String("go_version", os.Getenv("GO_VERSION")),
slog.String("listen", cfg.Server.Listen),
)
// Check if ffprobe is available
if err := checkFFProbe(); err != nil {
log.Warn("ffprobe not found, stream validation will be limited", slog.String("error", err.Error()))
}
// Create API server
apiServer, err := api.NewServer(cfg, log)
if err != nil {
log.Error("failed to create API server", err)
os.Exit(1)
}
// Create Web UI server
webuiServer := webui.NewServer(log)
// Create unified router combining API and WebUI
unifiedRouter := chi.NewRouter()
// Mount API routes at /api/v1/*
unifiedRouter.Mount("/api/v1", apiServer.GetRouter())
// Mount WebUI routes at /* (serves everything else including root)
unifiedRouter.Mount("/", webuiServer.GetRouter())
// Create unified HTTP server
httpServer := &http.Server{
Addr: cfg.Server.Listen,
Handler: unifiedRouter,
ReadTimeout: cfg.Server.ReadTimeout,
WriteTimeout: cfg.Server.WriteTimeout,
IdleTimeout: 120 * time.Second,
}
// Start server in goroutine
go func() {
log.Info("server starting",
slog.String("address", httpServer.Addr),
slog.String("api_version", "v1"),
)
if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Error("server failed", err)
os.Exit(1)
}
}()
// Print endpoints
printEndpoints(cfg.Server.Listen)
// Wait for interrupt signal
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
<-quit
log.Info("shutting down server...")
// Graceful shutdown with timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// Shutdown server
if err := httpServer.Shutdown(ctx); err != nil {
log.Error("server shutdown failed", err)
os.Exit(1)
}
log.Info("server stopped gracefully")
}
// checkFFProbe checks if ffprobe is available
func checkFFProbe() error {
// Try to execute ffprobe -version
cmd := os.Getenv("PATH")
if cmd == "" {
return fmt.Errorf("PATH environment variable not set")
}
// For now, just check if ffprobe exists in common locations
locations := []string{
"/usr/bin/ffprobe",
"/usr/local/bin/ffprobe",
"/opt/homebrew/bin/ffprobe",
}
for _, loc := range locations {
if _, err := os.Stat(loc); err == nil {
return nil
}
}
return fmt.Errorf("ffprobe not found in common locations")
}
// getLocalIP returns the local IP address of the machine
func getLocalIP() string {
addrs, err := net.InterfaceAddrs()
if err != nil {
return "localhost"
}
for _, addr := range addrs {
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
return ipnet.IP.String()
}
}
}
return "localhost"
}
// printEndpoints prints available endpoints
func printEndpoints(listen string) {
// Extract port from listen address
port := "4567"
if len(listen) > 0 {
if listen[0] == ':' {
port = listen[1:]
} else {
// Parse host:port format
for i := len(listen) - 1; i >= 0; i-- {
if listen[i] == ':' {
port = listen[i+1:]
break
}
}
}
}
// Get local IP
localIP := getLocalIP()
url := fmt.Sprintf("http://%s:%s", localIP, port)
// ANSI escape codes for clickable link (OSC 8 hyperlink)
clickableURL := fmt.Sprintf("\033]8;;%s\033\\%s\033]8;;\033\\", url, url)
fmt.Println("\n🌐 Web Interface:")
fmt.Println("────────────────────────────────────────────────")
fmt.Printf(" Open in browser: %s\n", clickableURL)
fmt.Println("────────────────────────────────────────────────")
fmt.Println("\n📚 Documentation: https://github.com/eduard256/Strix")
}
-517
View File
@@ -1,517 +0,0 @@
# 📹 IoT2mqtt Camera Database Format Specification
**Version:** 1.0.0
**Last Updated:** 2025-10-17
---
## 🎯 Overview
The camera database is a collection of JSON files containing URL patterns and connection details for IP cameras from various manufacturers. This format is designed to be:
- **Universal**: Works with any IP camera brand
- **Extensible**: Easy to add new models and protocols
- **Human-readable**: Simple JSON structure
- **Parseable**: Straightforward for automated tools
---
## 📁 Directory Structure
```
connectors/cameras/data/brands/
├── index.json # Master list of all brands
├── d-link.json # D-Link camera models
├── hikvision.json # Hikvision camera models
├── dahua.json # Dahua camera models
├── axis.json # Axis camera models
└── ... # Additional brands
```
---
## 📋 File Formats
### 1. **index.json** - Brand Directory
Lists all available camera brands with metadata.
```json
[
{
"value": "d-link",
"label": "D-Link",
"models_count": 250,
"entries_count": 85,
"logo": "/assets/brands/d-link.svg"
},
{
"value": "hikvision",
"label": "Hikvision",
"models_count": 320,
"entries_count": 95,
"logo": "/assets/brands/hikvision.svg"
}
]
```
**Fields:**
- `value` (string, required): Brand identifier (lowercase, URL-safe)
- `label` (string, required): Display name
- `models_count` (integer): Total number of camera models
- `entries_count` (integer): Number of URL pattern entries
- `logo` (string, optional): Path to brand logo
---
### 2. **{brand}.json** - Brand Camera Database
Contains all URL patterns and connection details for a specific brand.
```json
{
"brand": "D-Link",
"brand_id": "d-link",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"website": "https://www.dlink.com",
"entries": [
{
"models": ["DCS-930L", "DCS-930LB", "DCS-930LB1"],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "live3.sdp",
"notes": "Main HD stream"
},
{
"models": ["DCS-930L", "DCS-932L"],
"type": "MJPEG",
"protocol": "http",
"port": 80,
"url": "video.cgi?resolution=VGA",
"notes": "Medium quality fallback"
}
]
}
```
**Root Fields:**
- `brand` (string, required): Brand display name
- `brand_id` (string, required): Brand identifier (must match filename)
- `last_updated` (string, ISO 8601 date): When database was last updated
- `source` (string): Where the data came from (e.g., "ispyconnect.com")
- `website` (string, optional): Manufacturer's official website
- `entries` (array, required): List of URL pattern entries
---
### 3. **Entry Object** - URL Pattern Entry
Each entry represents a specific URL pattern that works for one or more camera models.
```json
{
"models": ["DCS-930L", "DCS-930LB", "DCS-930LB1"],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "live3.sdp",
"auth_required": true,
"notes": "Main HD stream with audio"
}
```
**Fields:**
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `models` | array[string] | ✅ Yes | List of camera model names/numbers this URL works for |
| `type` | string | ✅ Yes | Stream type: `FFMPEG`, `MJPEG`, `JPEG`, `VLC`, `H264` |
| `protocol` | string | ✅ Yes | Protocol: `rtsp`, `http`, `https` |
| `port` | integer | ✅ Yes | Port number (554 for RTSP, 80/443 for HTTP) |
| `url` | string | ✅ Yes | URL path (without protocol/host/port) |
| `auth_required` | boolean | No | Whether authentication is needed (default: true) |
| `notes` | string | No | Human-readable description |
---
## 🔧 URL Template Variables
URL paths support the following template variables:
| Variable | Description | Example |
|----------|-------------|---------|
| `{username}` | Camera username | `admin` |
| `{password}` | Camera password | `12345` |
| `{ip}` | Camera IP address | `192.168.1.100` |
| `{port}` | Port number | `554` |
| `{channel}` | Camera channel (for DVRs) | `1` |
| `{width}` | Video width | `1920` |
| `{height}` | Video height | `1080` |
**Example:**
```
Template: rtsp://{username}:{password}@{ip}:{port}/live3.sdp
Result: rtsp://admin:12345@192.168.1.100:554/live3.sdp
```
---
## 📊 Stream Types
### FFMPEG (Recommended)
- **Protocol**: RTSP, HTTP
- **Format**: H.264, H.265
- **Use case**: High-quality video with audio
- **Priority**: 🥇 First choice
### MJPEG
- **Protocol**: HTTP
- **Format**: Motion JPEG
- **Use case**: Medium quality, wide compatibility
- **Priority**: 🥈 Second choice
### JPEG
- **Protocol**: HTTP
- **Format**: Still images
- **Use case**: Snapshot-only cameras or fallback
- **Priority**: 🥉 Last resort
### VLC
- **Protocol**: RTSP, HTTP
- **Format**: Various (VLC-specific)
- **Use case**: Compatibility with VLC player
---
## 🎯 Priority Order for Testing
When testing multiple URLs for a camera model, use this priority:
1. **RTSP (type="FFMPEG")** - Best quality, supports audio
2. **HTTP MJPEG** - Good compatibility
3. **HTTP JPEG** - Snapshot fallback
**Example:**
```python
def get_urls_for_model(brand_data, model_name):
entries = [e for e in brand_data["entries"] if model_name in e["models"]]
# Sort by priority
priority = {"FFMPEG": 1, "MJPEG": 2, "JPEG": 3, "VLC": 4}
entries.sort(key=lambda e: priority.get(e["type"], 99))
return entries
```
---
## 🔍 Search and Lookup
### By Brand
```python
# Load brand file
with open(f"data/brands/{brand_id}.json") as f:
brand_data = json.load(f)
```
### By Model
```python
# Find all entries for a specific model
def find_model_entries(brand_data, model_name):
return [
entry for entry in brand_data["entries"]
if model_name.upper() in [m.upper() for m in entry["models"]]
]
```
### Fuzzy Search
```python
# Search across all models (case-insensitive, partial match)
def search_model(brand_data, query):
query = query.upper()
results = []
for entry in brand_data["entries"]:
if any(query in model.upper() for model in entry["models"]):
results.append(entry)
return results
```
---
## 🌐 URL Construction
### RTSP URL
```python
def build_rtsp_url(entry, ip, username, password):
return f"rtsp://{username}:{password}@{ip}:{entry['port']}/{entry['url']}"
# Example:
# rtsp://admin:12345@192.168.1.100:554/live3.sdp
```
### HTTP URL
```python
def build_http_url(entry, ip, username, password):
protocol = entry["protocol"] # "http" or "https"
return f"{protocol}://{username}:{password}@{ip}:{entry['port']}/{entry['url']}"
# Example:
# http://admin:12345@192.168.1.100:80/video.cgi?resolution=VGA
```
### With Template Variables
```python
def build_url(entry, ip, username, password, **kwargs):
url_path = entry["url"]
# Replace template variables
replacements = {
"username": username,
"password": password,
"ip": ip,
"port": str(entry["port"]),
**kwargs # Additional variables (channel, width, height, etc.)
}
for key, value in replacements.items():
url_path = url_path.replace(f"{{{key}}}", value)
# Build full URL
if entry["protocol"] == "rtsp":
return f"rtsp://{username}:{password}@{ip}:{entry['port']}/{url_path}"
else:
return f"{entry['protocol']}://{username}:{password}@{ip}:{entry['port']}/{url_path}"
```
---
## ✅ Validation Rules
### Entry Validation
```python
def validate_entry(entry):
# Required fields
assert "models" in entry and isinstance(entry["models"], list)
assert len(entry["models"]) > 0
assert "type" in entry and entry["type"] in ["FFMPEG", "MJPEG", "JPEG", "VLC", "H264"]
assert "protocol" in entry and entry["protocol"] in ["rtsp", "http", "https"]
assert "port" in entry and isinstance(entry["port"], int)
assert "url" in entry and isinstance(entry["url"], str)
# Port ranges
assert 1 <= entry["port"] <= 65535
# Common ports check
if entry["protocol"] == "rtsp":
assert entry["port"] in [554, 8554, 7447] # Common RTSP ports
elif entry["protocol"] == "http":
assert entry["port"] in [80, 8080, 8000, 8081] # Common HTTP ports
```
---
## 📝 Naming Conventions
### Brand IDs
- **Format**: lowercase, kebab-case
- **Examples**: `d-link`, `hikvision`, `tp-link`
- **Invalid**: `D-Link`, `D_Link`, `dlink`
### Model Names
- **Format**: UPPERCASE with hyphens (as manufacturer specifies)
- **Examples**: `DCS-930L`, `DS-2CD2142FWD-I`, `IPC-HFW1230S`
- **Keep original**: Don't normalize or change manufacturer names
### Protocol Values
- `rtsp` - RTSP protocol
- `http` - HTTP protocol
- `https` - HTTPS protocol
- **Invalid**: `RTSP`, `Http`, `tcp`
### Type Values
- `FFMPEG` - H.264/H.265 streams (RTSP or HTTP)
- `MJPEG` - Motion JPEG streams
- `JPEG` - Still image snapshots
- `VLC` - VLC-specific streams
---
## 🔄 Versioning and Updates
### Version Format
```json
{
"brand": "D-Link",
"brand_id": "d-link",
"database_version": "1.2.0",
"last_updated": "2025-10-17T14:30:00Z",
"entries": [...]
}
```
### Update Policy
- **Patch** (1.0.x): Add new models to existing entries
- **Minor** (1.x.0): Add new URL patterns/entries
- **Major** (x.0.0): Breaking changes to structure
---
## 📚 Examples
### Complete Brand File Example
**foscam.json:**
```json
{
"brand": "Foscam",
"brand_id": "foscam",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"website": "https://www.foscam.com",
"entries": [
{
"models": ["FI9821P", "FI9826P", "FI9821W"],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "videoMain",
"notes": "Main stream HD"
},
{
"models": ["FI9821P", "FI9826P"],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "videoSub",
"notes": "Sub stream SD"
},
{
"models": ["FI9821P", "FI9826P", "FI9821W", "C1"],
"type": "MJPEG",
"protocol": "http",
"port": 88,
"url": "cgi-bin/CGIStream.cgi?cmd=GetMJStream&usr={username}&pwd={password}",
"notes": "MJPEG fallback"
},
{
"models": ["FI9821P", "C1", "C2"],
"type": "JPEG",
"protocol": "http",
"port": 88,
"url": "cgi-bin/CGIProxy.fcgi?cmd=snapPicture2&usr={username}&pwd={password}",
"notes": "Snapshot"
}
]
}
```
---
## 🛠️ Tools and Scripts
### Parser Script (Python)
```python
# scripts/parse_ispyconnect.py
import requests
from bs4 import BeautifulSoup
import json
def parse_brand_page(brand_id):
url = f"https://www.ispyconnect.com/camera/{brand_id}"
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
table = soup.find('table', class_='table-striped')
entries = []
for row in table.find_all('tr')[1:]: # Skip header
cols = row.find_all('td')
if len(cols) < 4:
continue
models_text = cols[0].get_text()
models = [m.strip() for m in models_text.split(',')]
entry = {
"models": models,
"type": cols[1].get_text(strip=True),
"protocol": cols[2].get_text(strip=True).replace('://', ''),
"port": int(row.get('data-port', 0)),
"url": cols[3].get_text(strip=True)
}
entries.append(entry)
return {
"brand": brand_id.title(),
"brand_id": brand_id,
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": entries
}
```
### Validator Script
```python
# scripts/validate_database.py
import json
import os
def validate_brand_file(filepath):
with open(filepath) as f:
data = json.load(f)
# Check required fields
assert "brand" in data
assert "brand_id" in data
assert "entries" in data
# Validate each entry
for i, entry in enumerate(data["entries"]):
assert "models" in entry, f"Entry {i} missing models"
assert "type" in entry, f"Entry {i} missing type"
assert "protocol" in entry, f"Entry {i} missing protocol"
assert "port" in entry, f"Entry {i} missing port"
assert "url" in entry, f"Entry {i} missing url"
print(f"{filepath} is valid")
# Run validation
for file in os.listdir('data/brands/'):
if file.endswith('.json') and file != 'index.json':
validate_brand_file(f'data/brands/{file}')
```
---
## 📄 License and Attribution
- **Source**: ispyconnect.com camera database
- **Usage**: Free for IoT2mqtt project
- **Attribution**: Must credit ispyconnect.com as data source
- **Updates**: Community-contributed updates welcome
---
## 🤝 Contributing
To add or update camera models:
1. Follow the JSON format specification
2. Validate using `scripts/validate_database.py`
3. Test URLs with real cameras when possible
4. Submit pull request with changes
---
## 📞 Support
For questions about the database format:
- GitHub Issues: https://github.com/eduard256/Strix/issues
- Documentation: https://github.com/eduard256/Strix#readme
---
**End of Specification**
-258
View File
@@ -1,258 +0,0 @@
{
"brand": "255 Ip Cam",
"brand_id": "255-ip-cam",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"255",
"32X 5MP",
"C6F0SgZ3N0PfL2",
"C6F0SoZ3N0P9L2",
"CF0Sgzonopfl2",
"DENVER IPO-1320MK2",
"DRC6F0SgZ3N0P6L2",
"es cam g02",
"HW0029",
"ICAM",
"IIII-551433-ABEBF",
"IUK 5A1",
"Other",
"phr04k",
"pppp-216658-ecdcb",
"ProeliteIP01axBLK",
"q52-5mp-wh",
"SRICAM",
"tttt-489242-vxvmx",
"xly0144"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 5544,
"url": "/11"
},
{
"models": [
"255",
"ICAM",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.jpg"
},
{
"models": [
"255",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 5544,
"url": "/0"
},
{
"models": [
"3030",
"C6F0SoZ3N0P9L2",
"IIII-259624-EAADF",
"IUK 5A1",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/1"
},
{
"models": [
"4455",
"IPC365"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "ch0_0.h264"
},
{
"models": [
"C9F0SgZ3N0PbL0"
],
"type": "JPEG",
"protocol": "http",
"port": 8082,
"url": "/tmpfs/auto.jpg"
},
{
"models": [
"common"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]*[HEIGHT]"
},
{
"models": [
"H.265"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"icam",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/user=[USERNAME]_password=[PASSWORD]_channel=1_stream=0.sdp"
},
{
"models": [
"ICAM",
"Other",
"PoE"
],
"type": "JPEG",
"protocol": "http",
"port": 5544,
"url": "tmpfs/auto.jpg"
},
{
"models": [
"ip66minicam"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/1/h264major"
},
{
"models": [
"Ipc"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Ipc",
"ip-camera",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 80,
"url": "/snapshot.jpg"
},
{
"models": [
"IPC-V380-Q79"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/onvif1"
},
{
"models": [
"IUK 5A1",
"Other",
"sricam"
],
"type": "MJPEG",
"protocol": "http",
"port": 81,
"url": "videostream.cgi?rate=0&user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"kiina"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snap.jpg?JpegCam=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "image.jpg"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videofeed"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&password=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 10554,
"url": "1/h264major"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "/video.mp4"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=320*240"
},
{
"models": [
"sioplus"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/video1"
},
{
"models": [
"top"
],
"type": "FFMPEG",
"protocol": "http",
"port": 8080,
"url": "/videofeed"
}
]
}
-54
View File
@@ -1,54 +0,0 @@
{
"brand": "2n Helios",
"brand_id": "2n-helios",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"IP-CAMERA"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "tmpfs/auto.jpg"
},
{
"models": [
"IP-CAMERA",
"Vario"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/h264_stream"
},
{
"models": [
"IP-CAMERA"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?usr=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"VARIO"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot/view[CHANNEL].jpg"
},
{
"models": [
"VARIO"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?loginuse=[USERNAME]&loginpas=[PASSWORD]"
}
]
}
-44
View File
@@ -1,44 +0,0 @@
{
"brand": "307 Hi Silicon",
"brand_id": "307-hi-silicon",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"101"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.jpg"
},
{
"models": [
"318e"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "user=[USERNAME]&password=[PASSWORD]&channel=1&stream=0.sdp?"
},
{
"models": [
"HI3516C"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/0"
},
{
"models": [
"HI3518E"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/11"
}
]
}
-266
View File
@@ -1,266 +0,0 @@
{
"brand": "360 Eye",
"brand_id": "360-eye",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"1111",
"EC101-B3Y2",
"EC107-B3Y2",
"EC107Y-B3Y10",
"EC38",
"EC73-V13",
"EC76-U15",
"Other",
"v380",
"V380"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor"
},
{
"models": [
"360",
"V380"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 5544,
"url": "/11"
},
{
"models": [
"360"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 5544,
"url": "/0"
},
{
"models": [
"360",
"360eye",
"360Eye",
"360EYE",
"360EYE PRO",
"EC101-X15",
"EC76",
"EC76-U15",
"EC80_V13",
"EC80-X15",
"i360",
"Other",
"v380",
"V380"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "live/ch00_0"
},
{
"models": [
"360",
"360Eye Pro"
],
"type": "VLC",
"protocol": "rtsp",
"port": 1935,
"url": "LowResolutionVideo"
},
{
"models": [
"360eye",
"EC101-X15",
"EC107-B3Y2",
"EC107Y-B3Y10",
"EC73-N13",
"IPC365",
"v380"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=1&subtype=00&authbasic=[AUTH]"
},
{
"models": [
"360EYE",
"360Eye Pro",
"EC101Y-B3Y10",
"IPC365"
],
"type": "VLC",
"protocol": "rtsp",
"port": 5544,
"url": "live_mpeg4.sdp"
},
{
"models": [
"360EYE",
"360EYE PRO",
"EC101-X15",
"EC107-B3Y2",
"EC73-N13",
"EC76",
"EC76-U15",
"eyes",
"IPC365",
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam/realmonitor?channel=[CHANNEL]&subtype=1"
},
{
"models": [
"360EYE EC129-X15",
"EC101-B3Y2",
"EC101-X15",
"EC101Y-B3Y10",
"EC107-X15",
"EC37",
"EC73-N13",
"EC73-V13",
"PW2K2N06E-GTWY"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=0&subtype=1"
},
{
"models": [
"603",
"Other",
"V380"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "tmpfs/auto.jpg"
},
{
"models": [
"E101-B3Y2",
"EC101Y-B3Y10"
],
"type": "VLC",
"protocol": "rtsp",
"port": 1935,
"url": "ch0_0.h264"
},
{
"models": [
"EC101-B3Y2",
"EC107-B3Y2",
"EC76-X15",
"epc101",
"Other",
"v380",
"V380 Wifi IP Cam"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/live/ch00_0"
},
{
"models": [
"EC101-X15",
"EC132-X15",
"EC80-X15"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=8080&subtype=1"
},
{
"models": [
"EC101-X15",
"mv12241966"
],
"type": "FFMPEG",
"protocol": "mms",
"port": 554,
"url": "/img/video.asf"
},
{
"models": [
"EC101-X15",
"PW2L2A06A-GTY"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=1&subtype=1"
},
{
"models": [
"EC107-B3Y2",
"EC73-N13"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/LowResolutionVideo"
},
{
"models": [
"EC107-B3Y2"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/live_mpeg4.sdp"
},
{
"models": [
"EC107-X15",
"EC137-X15",
"EC80-X15",
"XM80-8MP"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/realmonitor?channel=0&stream=0.sdp"
},
{
"models": [
"EC137Y-B3Y2"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/ch0_0.h264"
},
{
"models": [
"SL-CAM",
"V380",
"y335"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/onvif1"
},
{
"models": [
"V380"
],
"type": "VLC",
"protocol": "mms",
"port": 0,
"url": "img/video.asf"
}
]
}
-151
View File
@@ -1,151 +0,0 @@
{
"brand": "3com",
"brand_id": "3com",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"EX11402-WIFI",
"Other",
"rc8221",
"XHCI-SE"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=2"
},
{
"models": [
"EX11402-WIFI",
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]*[HEIGHT]"
},
{
"models": [
"EX11402-WIFI",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"Ipela"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "goform/video2"
},
{
"models": [
"IPELA",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "mjpeg.cgi?user=[USERNAME]&password=[PASSWORD]&channel=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?usr=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"Other",
"RC8221"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?loginuse=[USERNAME]&loginpas=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.jpg?user=[USERNAME]&pwd=[PASSWORD]&strm=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "jpg/image.jpg?size=3"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.jpg?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/net_jpeg.cgi?ch=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video?submenu=mjpg"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other",
"RC8221"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=3"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "3eyes3",
"brand_id": "3eyes3",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"E-2100M"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 5544,
"url": "/11"
}
]
}
-474
View File
@@ -1,474 +0,0 @@
{
"brand": "3g Ipcam",
"brand_id": "3g-ipcam",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"002a",
"720 P IP CAMERA",
"L Series",
"Other",
"SRICAM SP004"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?usr=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"002A",
"IPCAM V380",
"IPC-HFW2231R-ZS-IRE6",
"Other",
"P2P"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?loginuse=[USERNAME]&loginpas=[PASSWORD]"
},
{
"models": [
"002A",
"720 P IP CAMERA",
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"002A",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"1234",
"C6F0SEZ0N0P0L0",
"C6F0SFZ3NOP5L0",
"C6F0SGZ0N0P3L0",
"C6F0SGZ3N0P6L2",
"C6F0SiZ3N0P0L0",
"C6F0SoZ3N0PcL2",
"C9F0SeZ0N0P4L0",
"C9F0SEZ0N0P4L0",
"C9F0SGZ0N0P2L1",
"C9F0SgZ3NP8L0",
"Chemin",
"F-SERIES",
"Other",
"SRICAM"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 5544,
"url": "/11"
},
{
"models": [
"2016w"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?usr=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"2018",
"F-series",
"P2P"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]*[HEIGHT]"
},
{
"models": [
"3245",
"328",
"3285",
"3289",
"454",
"4556",
"546577",
"720 P IP CAMERA",
"B987w",
"BM16",
"C6F0SeZ0N0P0L0",
"C6F0SfZ0N0P3L0",
"C6F0SfZ3NOP5L0",
"C6F0SgZ0N0P3L0",
"C6F0SgZ3N0P6L2",
"C6F0SIZ3N0P0L0",
"C9F0SgZ0N0P2L1",
"CT0276WHUK",
"Fd7902",
"GGGG-152116-FCEEA",
"L SERIES",
"Other",
"p2p",
"sr1",
"SRICAM SP004"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "tmpfs/auto.jpg"
},
{
"models": [
"355566",
"546577",
"Other",
"X6130"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.jpg?user=[USERNAME]&pwd=[PASSWORD]&strm=[CHANNEL]"
},
{
"models": [
"3g Ipcam: C6F0SoZ3N0PdL2"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/stream_0"
},
{
"models": [
"3g Ipcam: C6F0SoZ3N0PdL2"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/1/h264major"
},
{
"models": [
"556",
"c6f0SoZ3n0P9L2",
"ipc"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/ch0_0.264"
},
{
"models": [
"590"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "iphone/11?[USERNAME]:[PASSWORD]&"
},
{
"models": [
"720 P IP CAMERA",
"IPC701939"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/onvif1"
},
{
"models": [
"720 P IP CAMERA"
],
"type": "JPEG",
"protocol": "http",
"port": 80,
"url": "/snapshot.jpg?user=[USERNAME]&pwd=[PASSWORD]&strm=2"
},
{
"models": [
"720 P IP CAMERA"
],
"type": "JPEG",
"protocol": "http",
"port": 80,
"url": "/snapshot.jpg?user=[USERNAME]&pwd=[PASSWORD]&strm=0"
},
{
"models": [
"720 P IP CAMERA"
],
"type": "JPEG",
"protocol": "http",
"port": 80,
"url": "/snapshot.jpg"
},
{
"models": [
"C6F0SEZ0N0P0L0",
"c9F0SeZ0N0P4L0",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snap.jpg?JpegCam=[CHANNEL]"
},
{
"models": [
"C6F0SFZ0N0P3L0",
"PPCN060874FEGNW"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=2"
},
{
"models": [
"C6F0SGZ3N0P6L2",
"C9F0SeZ0N0P7L0",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/1"
},
{
"models": [
"C9F0SEZ0N0P7L0"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 10554,
"url": "1/h264major"
},
{
"models": [
"ipc720"
],
"type": "JPEG",
"protocol": "http",
"port": 80,
"url": "/snapshot.jpg?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"IP-CAM"
],
"type": "VLC",
"protocol": "mms",
"port": 0,
"url": "img/video.asf"
},
{
"models": [
"IP-CAM"
],
"type": "FFMPEG",
"protocol": "mms",
"port": 554,
"url": "/img/video.asf"
},
{
"models": [
"IPCAM v380",
"IPCAM V380"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "live/ch00_0"
},
{
"models": [
"IPCAM V380",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.jpg?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"IPCAM V380",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 10554,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"IPCAM V380",
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam[CHANNEL]/h264"
},
{
"models": [
"L SERIES",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?rate=11"
},
{
"models": [
"L SERIES",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videofeed"
},
{
"models": [
"NEXHT360"
],
"type": "VLC",
"protocol": "rtsp",
"port": 1935,
"url": "/cam/realmonitor?channel=1&subtype=00&authbasic=[AUTH]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "live?camera=[CHANNEL]&fps=5&quality=75&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.cgi?resolution=VGA"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?rate=0&user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video?submenu=mjpg"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "image.jpg"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.mjpg?q=30&fps=33&id=0.5"
},
{
"models": [
"Other",
"P2P"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 10554,
"url": "/tcp/av0_0"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "api/mjpegvideo.cgi?InputNumber=1&StreamNumber=[CHANNEL]"
},
{
"models": [
"rc8025"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=3"
},
{
"models": [
"SCRICAM AP004",
"SRICAM AP006"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
}
]
}
-64
View File
@@ -1,64 +0,0 @@
{
"brand": "3r",
"brand_id": "3r",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"Other",
"Prestige DVR",
"PRESTİGE DVR"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "current[CHANNEL].jpg"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam[CHANNEL]/h264"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "ipcam/avc.cgi?audiostream=[CHANNEL]"
},
{
"models": [
"Prestige DVR"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "image/[CHANNEL].jpg"
},
{
"models": [
"Prestige DVR"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "/control/faststream.jpg?stream=MxPEG&needlength&fps=6"
}
]
}
-251
View File
@@ -1,251 +0,0 @@
{
"brand": "3svision",
"brand_id": "3svision",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"N3011",
"N6078",
"N6079"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/cam1/onvif-h264"
},
{
"models": [
"N3071",
"N6078",
"N9071",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam1/onvif-h264-1"
},
{
"models": [
"N3072",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "image.jpg"
},
{
"models": [
"N6013"
],
"type": "MJPEG",
"protocol": "http",
"port": 80,
"url": "/axis-cgi/mjpg/video.cgi"
},
{
"models": [
"N6071",
"N8072",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "axis-cgi/mjpg/video.cgi"
},
{
"models": [
"N6076"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/11"
},
{
"models": [
"N8072"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "image/[CHANNEL].jpg"
},
{
"models": [
"N8072",
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam[CHANNEL]/h264"
},
{
"models": [
"N9073"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "axis-cgi/mjpg/video.cgi?date=1&clock=1&camera=[CHANNEL]&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snap.jpg?JpegCam=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=2"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?loginuse=[USERNAME]&loginpas=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/video.jpg"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "GetData.cgi"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "cgi-bin/view.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam1/mpeg4"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam2/mpeg4"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam3/mpeg4"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam4/mpeg4"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "current[CHANNEL].jpg"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videofeed"
}
]
}
-245
View File
@@ -1,245 +0,0 @@
{
"brand": "3xlogic",
"brand_id": "3xlogic",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"3mp",
"vsx"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/video.h264"
},
{
"models": [
"3mp",
"CMC-3MP-OD-I",
"VSX-2MP-MVD40",
"VX-3P28-OD-I"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/Streaming/Channels/1"
},
{
"models": [
"3mp"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/"
},
{
"models": [
"avtech",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/guest/Video.cgi?media=JPEG&channel=[CHANNEL]"
},
{
"models": [
"AVTECH",
"vsx-2mp-d",
"VX-3PV-B-I",
"VX-4S28-MD-I"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "live/mpeg4"
},
{
"models": [
"Other",
"vsx-2m-d",
"VSX-2MP-MVD40"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "video.h264"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?loginuse=[USERNAME]&loginpas=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "jpg/1/image.jpg"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videofeed"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "cgi-bin/view.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "ch0_0.h264"
},
{
"models": [
"Radio"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?rate=0&user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"rc8025"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=3"
},
{
"models": [
"Vigil Server"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "live?camera=[CHANNEL]&quality=75&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Vigil Server"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "live?camera=[USERNAME]&quality=75&resolution=[PASSWORD]"
},
{
"models": [
"Vigil Server"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "live?camera=[USERNAME]&quality=75&fps=5&resolution=[PASSWORD]"
},
{
"models": [
"Vigil Server"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "live?camera=[CHANNEL]&fps=5&quality=75&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"vsx",
"VX-3P28-MD-IA"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/ch0_0.h264"
},
{
"models": [
"VSX-2MP-MVD40"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "img/video.mjpeg"
},
{
"models": [
"VX-3M-F-AWD",
"VX-3m-OD2-RIAWD"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 555,
"url": "/11"
},
{
"models": [
"VX-3P28-MD-IA"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/stream0"
},
{
"models": [
"VX-4S28-MD-I"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=1&subtype=00&authbasic=[AUTH]"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "4er",
"brand_id": "4er",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/live/av0"
}
]
}
-85
View File
@@ -1,85 +0,0 @@
{
"brand": "4mp Ip Camera",
"brand_id": "4mp-ip-camera",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"47680146",
"KEYE",
"Other",
"Security"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 5544,
"url": "/11"
},
{
"models": [
"g-240",
"G42"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"ID002A",
"IPB8224"
],
"type": "VLC",
"protocol": "http",
"port": 81,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"ipc-2mpvd28w"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/h264_stream"
},
{
"models": [
"ipc-2mpvd28w"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/?action=stream"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "VIDEO.CGI"
},
{
"models": [
"uniview"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/onvif-stream2"
},
{
"models": [
"zero"
],
"type": "FFMPEG",
"protocol": "http",
"port": 8090,
"url": "/video.mjpg?q=30&fps=33&id=0.5"
}
]
}
-72
View File
@@ -1,72 +0,0 @@
{
"brand": "4sdot",
"brand_id": "4sdot",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"4331911061",
"4S-B05W-720P",
"B05W-720"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "tmpfs/auto.jpg"
},
{
"models": [
"4S-B05W-720P",
"B05W-720P",
"CMOS720P",
"hx series"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snap.jpg?JpegCam=[CHANNEL]"
},
{
"models": [
"B05W-720P",
"B07BW-1080P-HX",
"HX series",
"HX SERIES",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/11"
},
{
"models": [
"B07BW-1080P-HX",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/1"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/live/av0"
},
{
"models": [
"PW638K"
],
"type": "MJPEG",
"protocol": "http",
"port": 81,
"url": "videostream.cgi"
}
]
}
-209
View File
@@ -1,209 +0,0 @@
{
"brand": "4ucam",
"brand_id": "4ucam",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Eyes DVR",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "/cgi-bin/Stream?Video?Acc=[USERNAME]?Pwd=[PASSWORD]?webcamPWD=UserCookie00000"
},
{
"models": [
"EYES DVR",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"EYES DVR",
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "shot.jpg"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/Stream?Video?Acc=[USERNAME]?Pwd=[PASSWORD]?webcamPWD=UserCookie00000"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.cgi?resolution=VGA"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/cam/realmonitor"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "stream.asf"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/guest/Video.cgi?media=JPEG&channel=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/net_jpeg.cgi?ch=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?1"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=2"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "capture[CHANNEL].jpg"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "loginfree.jpg"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/video.jpg?cam=[CHANNEL]&quality=3&size=2"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "ch0_0.h264"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
}
]
}
-179
View File
@@ -1,179 +0,0 @@
{
"brand": "4xem",
"brand_id": "4xem",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"IP3112",
"IPCAMW45",
"Other",
"PT 3114",
"PZ6114",
"W50",
"WLPTG",
"WLPTS",
"WLPTZ",
"WPT",
"wptz"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/video.jpg?size=2"
},
{
"models": [
"IP3112",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videofeed"
},
{
"models": [
"IP3112"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?1"
},
{
"models": [
"IpCamW45",
"KX SERIES",
"Other",
"W45"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "live.sdp"
},
{
"models": [
"IPCAMW45",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.jpg?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"KX SERIES",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/video.jpg"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Other",
"PZ6114"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?loginuse=[USERNAME]&loginpas=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/net_jpeg.cgi?ch=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/video.jpg?cam=[CHANNEL]&quality=3&size=2"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.cgi?resolution=VGA"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32"
},
{
"models": [
"Other",
"Other3"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "cgi-bin/view.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"PT 3114"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/cgi-bin/video.jpg?cam=0&quality=3&size=2"
}
]
}
-26
View File
@@ -1,26 +0,0 @@
{
"brand": "4xptz",
"brand_id": "4xptz",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"30x"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "live_mpeg4.sdp"
},
{
"models": [
"M400"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/stream0"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "555",
"brand_id": "555",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "5mpbullet",
"brand_id": "5mpbullet",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/Onvif/live/1/1"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "7-star",
"brand_id": "7-star",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"WIPB-SC22"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
}
]
}
-727
View File
@@ -1,727 +0,0 @@
{
"brand": "7links",
"brand_id": "7links",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"3628-675",
"PX-3615-675"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]*[HEIGHT]"
},
{
"models": [
"3655",
"3786-675",
"IPC-440HD",
"IPC-710IR",
"Meins",
"Other",
"PX3309",
"PX3615",
"PX-3628-675",
"PX-3671-675 LHL",
"px-3688-675",
"px-3722-675",
"PX3744",
"Sitzplatz"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf"
},
{
"models": [
"3655",
"ipc-710ir",
"ipc-720",
"IP-CAM",
"PX 3675",
"PX3309",
"PX-3615"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"3655",
"7LinksCamBarn",
"IPC-380",
"IPC-720",
"IPC-720 HD",
"IPC-800.FHD",
"ipc900.ptz",
"NX4275",
"NX-4284-675",
"PX3615",
"PX-3688-675",
"PX-3755"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/live/ch0"
},
{
"models": [
"3671",
"3677",
"3677-675",
"3720-675",
"3720-919",
"3755",
"Incam",
"ipc-720",
"IPC-760HD",
"IPC-770HD",
"IP-Cam-in",
"Other",
"PX3309",
"PX-3671-675 LHL",
"px-3675",
"px-3719-675",
"px-3720-675",
"PX-3720-675",
"Überwachung"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"3671",
"3677",
"3677-675",
"3720-919",
"IPC-440.HD",
"ipc-710ir",
"IPC-710IR",
"IP-Cam-in",
"IP-Wi-Fi",
"lenacam",
"Other",
"PX 3675",
"px 3675-675",
"PX3309",
"PX3614_675",
"PX3615",
"px-3671",
"PX-3671-675 LHL",
"px-3688-675",
"px-3722-675",
"Px3722-675"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"3671",
"as",
"moja",
"Other",
"PX3614_12",
"PX3615",
"PX-3615-675",
"px-3671",
"RoboCam III"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"3677",
"374411",
"3755",
"ipc-20hd",
"IPC-340HD",
"IPC-440.HD",
"IPC440HD",
"IPC-720",
"IPC-770HD",
"IPC-850.FHD",
"Other",
"Px3722-675",
"px3744",
"PX-3744",
"Px3744-675",
"px3755",
"PX-3755",
"PX-3765-675",
"px-3775",
"PX-4760"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/CGIProxy.fcgi?cmd=snapPicture2&usr=[USERNAME]&pwd=[PASSWORD]&"
},
{
"models": [
"3677",
"HAUSTÜR",
"IPC-710IR",
"IP-WI-FI",
"Other",
"px-1179-675",
"px-1279",
"PX3309",
"PX3615",
"PX-3688-675",
"RoboCam II",
"ROBOCAM III",
"ÜBERWACHUNG",
"Wireless"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi/mjpg/mjpeg.cgi"
},
{
"models": [
"3677",
"IPC-430 WIFI",
"IPC-631.HD",
"IP-CAM",
"Other",
"PX-3615"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snap.jpg?JpegCam=[CHANNEL]"
},
{
"models": [
"3720-675",
"ipc-720 HD",
"IPC-760HD",
"IPC-770HD",
"Other",
"PX 3675",
"px 3675-675",
"PX-3671-675 LHL",
"PX36771-1",
"px-3720-675"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/video_snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"3720-675",
"ipc-720",
"NX-4558"
],
"type": "VLC",
"protocol": "rtsp",
"port": 5544,
"url": "ch0_0.h264"
},
{
"models": [
"3744",
"IPC 260",
"IPC-20HD",
"ipc900.ptz",
"Other",
"PX 3760-675",
"PX-3755-675"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "videoMain"
},
{
"models": [
"3775-675"
],
"type": "JPEG",
"protocol": "http",
"port": 88,
"url": "/cgi-bin/CGIProxy.fcgi?cmd=snapPicture2&usr=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"4336",
"IPC-20HD",
"IPC-430 WIFI",
"IPC-720 HD",
"IP-CAM-IN",
"nx-4341-675",
"NX-4341-675",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "tmpfs/auto.jpg"
},
{
"models": [
"CS131A",
"RoboCam",
"RoboCam II",
"RoboCam III"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi/jpg/image.cgi"
},
{
"models": [
"Haustür",
"IP-Wi-Fi",
"Other",
"PX3614_12",
"PX3615",
"px-3722-675"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?rate=11"
},
{
"models": [
"IPC-220.hd",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": ""
},
{
"models": [
"IPC-300"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 8554,
"url": "/Streaming/Channels/101"
},
{
"models": [
"IPC-340HD",
"ipc-380",
"IPC-770HD",
"IP-CAM",
"PX-37878"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 8554,
"url": "/live/av0"
},
{
"models": [
"IPC-400"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/av0_0"
},
{
"models": [
"IPC-430 WIFI",
"Other",
"PX3615"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?usr=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"IPC-440.HD",
"IPC-440HD",
"IPC-750HD",
"ipc900.ptz",
"NX-4207",
"NX-4209"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 80,
"url": "/videoMain"
},
{
"models": [
"IPC-440.HD",
"IPC-720",
"NX-4558-913"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 8554,
"url": "/live1.264"
},
{
"models": [
"IPC440HD",
"ipc900.ptz"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam/realmonitor?channel=[CHANNEL]&subtype=1"
},
{
"models": [
"IPC-440HD",
"ipc-720",
"Other",
"PX3309",
"PX3615",
"px-3675",
"px-3688-675"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.cgi?resolution=VGA"
},
{
"models": [
"ipc-631.hd",
"px-3690"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.mjpg"
},
{
"models": [
"ipc-631.hd",
"px-3690"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.mjpg?q=30&fps=33&id=0.5"
},
{
"models": [
"IPC-710IR",
"Other",
"PX3615",
"px-3690"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi"
},
{
"models": [
"ipc-720",
"IPC-720 HD",
"Other",
"PX3615",
"px-3690"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?"
},
{
"models": [
"IPC-720 HD",
"IP-CAM",
"nx 4389",
"NX-4389-675",
"Other",
"pano360s",
"SK7008-T1F1"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.jpg"
},
{
"models": [
"IPC-740"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 8554,
"url": "/Streaming/Channels/102"
},
{
"models": [
"IP-CAM",
"PX3614_675"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"IP-CAM",
"Other",
"PX3615"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?resolution=8&rate=13"
},
{
"models": [
"IP-Wi-Fi",
"Other",
"PX3615"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?rate=0&user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"KT-6764",
"PX-3744",
"RoboCam III"
],
"type": "MJPEG",
"protocol": "http",
"port": 80,
"url": "/?action=stream"
},
{
"models": [
"NX-4209"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 88,
"url": "/live/h264/ch0"
},
{
"models": [
"NX-4336-675"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/11"
},
{
"models": [
"NX-4389-675",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 88,
"url": "snapshot.jpg?user=[USERNAME]&pwd=[PASSWORD]&strm=[CHANNEL]"
},
{
"models": [
"Other",
"PX3615"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"Other",
"PX3309"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "video.cgi"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video?profile=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"px 3675-675",
"PX3615",
"px3723"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi"
},
{
"models": [
"px 3675-675"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=320*240"
},
{
"models": [
"PX3309",
"PX3615"
],
"type": "JPEG",
"protocol": "http",
"port": 80,
"url": "/snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"PX3614_675"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=320x240"
},
{
"models": [
"PX3615",
"SK7008-T1F1"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/Streaming/channels/401"
},
{
"models": [
"PX-3615-675"
],
"type": "FFMPEG",
"protocol": "http",
"port": 888,
"url": "/videostream.asf"
},
{
"models": [
"PX-3615-675"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&password=[PASSWORD]"
},
{
"models": [
"px-3688-675"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "?action=stream"
},
{
"models": [
"px-3690"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "jpg/image.jpg?size=3"
},
{
"models": [
"px-3690"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/"
},
{
"models": [
"RoboCam II",
"RoboCam III"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi/mjpg/mjpg.cgi"
},
{
"models": [
"RoboCam II"
],
"type": "JPEG",
"protocol": "http",
"port": 82,
"url": "/cgi/jpg/image.cgi"
},
{
"models": [
"RoboCam III"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "user/videostream.cgi"
},
{
"models": [
"RoboCam III"
],
"type": "FFMPEG",
"protocol": "http",
"port": 82,
"url": "/cgi/mjpg/mjpg.cgi"
}
]
}
-36
View File
@@ -1,36 +0,0 @@
{
"brand": "8level",
"brand_id": "8level",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"IPED-2MP-36-1",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snap.jpg?JpegCam=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/h264_stream"
},
{
"models": [
"v380"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 5544,
"url": "/11"
}
]
}
-53
View File
@@ -1,53 +0,0 @@
{
"brand": "9up",
"brand_id": "9up",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"DIP3"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=2"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/sf.cgi"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snap.jpg?JpegCam=[CHANNEL]"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "A-bmi",
"brand_id": "a-bmi",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]x[HEIGHT]"
}
]
}
-80
View File
@@ -1,80 +0,0 @@
{
"brand": "A-link",
"brand_id": "a-link",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"101",
"IPC1",
"IPC2",
"IPC3"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi/jpg/image.cgi"
},
{
"models": [
"101",
"IPC1",
"IPC2"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi/mjpg/mjpeg.cgi"
},
{
"models": [
"AICN500W",
"IPC1"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi/mjpg/mjpg.cgi"
},
{
"models": [
"IPC2"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"IPC3",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "image.cgi?resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"IPC3",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.cgi?resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"IPC3",
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "/Video?Codec=MPEG4&Width=720&Height=576&Fps=30"
}
]
}
-143
View File
@@ -1,143 +0,0 @@
{
"brand": "A-mtk",
"brand_id": "a-mtk",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"2570D",
"6566",
"Other",
"SUPER"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "media/media.amp"
},
{
"models": [
"6566",
"AM9539M",
"Dome",
"Other",
"SUPER"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "cgi-bin/net_video.cgi?channel=[CHANNEL]"
},
{
"models": [
"AH2927T-A"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/media.amp"
},
{
"models": [
"AH2927T-A",
"Dome",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "axis-cgi/mjpg/video.cgi"
},
{
"models": [
"AM2110D"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/media.amp?streamprofile=Profile1"
},
{
"models": [
"AM2110D"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/media.amp?streamprofile=Profile2"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam/realmonitor?channel=[CHANNEL]&subtype=00"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snap.jpg"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "capture[CHANNEL].jpg"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videofeed"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video?profile=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.cgi?resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.cgi?resolution=VGA"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "A-tion",
"brand_id": "a-tion",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"A0528"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/11"
}
]
}
-55
View File
@@ -1,55 +0,0 @@
{
"brand": "A1webcam",
"brand_id": "a1webcam",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/jpg.cgi?refresh=0&channel=[CHANNEL]&id=[USERNAME]&pass=[PASSWORD]&resolution=[WIDTH]x[HEIGHT]&oldbrowser=1"
},
{
"models": [
"Other",
"Phone"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videofeed"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]*[HEIGHT]"
},
{
"models": [
"tyytt"
],
"type": "MJPEG",
"protocol": "http",
"port": 8080,
"url": "/videofeed"
},
{
"models": [
"Wanscam",
"web1"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=2"
}
]
}
-141
View File
@@ -1,141 +0,0 @@
{
"brand": "A4tech",
"brand_id": "a4tech",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"432b",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/guest/Video.cgi?media=JPEG"
},
{
"models": [
"432b",
"avm457",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/guest/Video.cgi?media=JPEG&channel=[CHANNEL]"
},
{
"models": [
"AVM457",
"Ganek",
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?usr=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"AVM457",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"ITD2016",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.mjpg"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=2"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "image.jpg"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?rate=11"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "nphMotionJpeg?Resolution=640x480&Quality=Standard"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?rate=0&user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "GetData.cgi"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "[CHANNEL]/[USERNAME]:[PASSWORD]/main"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.mjpg?q=30&fps=33&id=0.5"
}
]
}
-24
View File
@@ -1,24 +0,0 @@
{
"brand": "Aanke",
"brand_id": "aanke",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"191BL",
"191BM",
"C500",
"C800",
"I51DL",
"I91BF",
"I91BN",
"I91-DX"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/user=[USERNAME]_password=[PASSWORD]_channel=1_stream=0.sdp"
}
]
}
-80
View File
@@ -1,80 +0,0 @@
{
"brand": "Abelcam",
"brand_id": "abelcam",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"005"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi/snapshot.cgi?action=getdata&channel.[CHANNEL].capture=true&channel.[CHANNEL].resolution=1"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/net_jpeg.cgi?ch=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "live/ch00_0"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videofeed"
},
{
"models": [
"WebCam (2)"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "current[CHANNEL].jpg"
},
{
"models": [
"WebCam (2)"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "current[CHANNEL].mjpg"
},
{
"models": [
"WebCam Server"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "screen.jpg"
},
{
"models": [
"WebCam Server"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "screen.mjpg"
}
]
}
-26
View File
@@ -1,26 +0,0 @@
{
"brand": "Abient Weather",
"brand_id": "abient-weather",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"AMBIENTCAMHD"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/CGIProxy.fcgi?cmd=snapPicture2&usr=[USERNAME]&pwd=[PASSWORD]&"
},
{
"models": [
"SK7008-T1F1"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 10554,
"url": "/Streaming/channels/601"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "Abo",
"brand_id": "abo",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Ranger Pro"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "Abr Security",
"brand_id": "abr-security",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"IPC6200W"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/11"
}
]
}
-32
View File
@@ -1,32 +0,0 @@
{
"brand": "Abr",
"brand_id": "abr",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"6100",
"720p",
"ipc6100w"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "tmpfs/auto.jpg"
},
{
"models": [
"6100",
"6200",
"ABR-IPD6200W",
"IPC6100W",
"IPD6200W"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/11"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "Abron",
"brand_id": "abron",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"AB-IPR506NB-US"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/rtsph2641080p"
}
]
}
-108
View File
@@ -1,108 +0,0 @@
{
"brand": "Abs",
"brand_id": "abs",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"3 series"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"3 series",
"4 series"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "mjpg/1/video.mjpg"
},
{
"models": [
"3 SERIES",
"4 SERIES",
"MegaCam",
"MegaCam 312M",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "jpg/1/image.jpg"
},
{
"models": [
"3 SERIES",
"4 SERIES",
"megacam 4210",
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "mpeg4/[CHANNEL]/media.amp"
},
{
"models": [
"4 series",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.cgi?resolution=VGA"
},
{
"models": [
"4 SERIES",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "mjpg/[CHANNEL]/video.mjpg"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/net_jpeg.cgi?ch=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?rate=0"
}
]
}
-35
View File
@@ -1,35 +0,0 @@
{
"brand": "Absolutron",
"brand_id": "absolutron",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "image.mpg"
},
{
"models": [
"ptz"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.jpg?user=[USERNAME]&pwd=[PASSWORD]&strm=[CHANNEL]"
}
]
}
-640
View File
@@ -1,640 +0,0 @@
{
"brand": "Abus",
"brand_id": "abus",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"10550",
"Other",
"TV21550",
"TVIP10500",
"TVIP10550",
"TVIP11000",
"TVIP20000",
"TVIP21550",
"TVIP51550",
"TVIP52501"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "jpg/image.jpg"
},
{
"models": [
"21501",
"Other",
"TVIP10001",
"TVIP10050",
"TVIP10051",
"TVIP21050",
"TVIP21500",
"TVIP31050",
"TVIP52501",
"tvip71000",
"TVIP71550"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "jpg/image.jpg?size=3"
},
{
"models": [
"2718",
"Digi-Lan TV7204",
"DIGI-LAN TV7219",
"Digi-Lan TV7230",
"DIGI-LAN TV7230 V2",
"Innenhof",
"Other",
"tv7202",
"TV7203",
"TV7210",
"TV7214",
"tv7216",
"tv7218",
"TV7240-LAN",
"TVIP51550"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/video.jpg"
},
{
"models": [
"ABUS: TVIP82100",
"IPCB64621",
"TVIP42561"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/user=[USERNAME]_password=[PASSWORD]_channel=1_stream=0.sdp"
},
{
"models": [
"casa",
"DIGI-LAN TV7230 V2",
"Other20550",
"TV7203",
"TV7220",
"TVIP41550",
"TVIP52500",
"TVIP52501"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/viewer/video.jpg?resolution=640x480"
},
{
"models": [
"CF3",
"ipcb42501",
"IPCB54611B",
"IPCB74521",
"IPCB78520",
"IPCS84530",
"TVIP11560",
"TVIP41500",
"TVIP42561",
"TVIP42562",
"TVIP44510",
"TVIP60000",
"TVIP61500",
"TVIP61550",
"TVIP61560",
"TVIP62000",
"TVIP62560"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/Streaming/Channels/1"
},
{
"models": [
"Digilan 7230",
"TV7204V2",
"tv7216",
"TV7230"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/video.jpg?size=2"
},
{
"models": [
"DIGILAN 7230",
"Digi-Lan TV7204",
"Digi-Lan TV7230",
"DIGI-LAN TV7230",
"DIGI-LAN TV7230 V2",
"entree",
"foyer",
"Other",
"Other20550",
"TV7203",
"tv7204",
"TV7220",
"TV7240-LAN",
"TVIP11000",
"TVIP21550",
"TVIP41550_CAM1",
"TVIP52500",
"TVIP61560"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "live.sdp"
},
{
"models": [
"Digi-Lan TV7204",
"Other",
"Other20550",
"TV7204v2",
"TV7222",
"TVIP41550",
"TVIP51550"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/viewer/video.jpg?channel=[CHANNEL]&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Digi-Lan TV7206",
"Digi-Lan TV7230 v2",
"TVIP41550",
"tvip52500",
"tvip52501",
"TVIP52501",
"TVIP60550"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/viewer/video.jpg"
},
{
"models": [
"Digi-Lan TV7206",
"Digi-Lan TV7230 v2",
"FENIX",
"HD720p Dome",
"Other",
"Other20550",
"TIVP 31500",
"TV21550",
"TV7203",
"TVIP10000",
"TVIP10001",
"TVIP10055",
"TVIP11000",
"TVIP11502",
"TVIP11551",
"TVIP11552",
"TVIP21500",
"TVIP21550",
"tvip21551",
"tvip21552",
"TVIP21552",
"TVIP21560",
"TVIP31551",
"TVIP32500",
"TVIP41550",
"TVIP51550",
"TVIP71501",
"TVIP71551",
"TVIP717551",
"tvipem"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.mjpg"
},
{
"models": [
"DVR90001"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/Streaming/Unicast/channels/101.sdp"
},
{
"models": [
"DVR9001"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/Streaming/Unicast/channels/102.sdp"
},
{
"models": [
"DVR9001"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/Streaming/Unicast/channels/202.sdp"
},
{
"models": [
"HDCC90001"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/Streaming/Unicast/channels/201.sdp"
},
{
"models": [
"IP17550",
"IPS17550",
"IR 1080p",
"tvip10550",
"TVIP21500",
"tvip21551",
"tvip21552",
"TVIP52500",
"TVIP61550",
"TVIP62560",
"TVIP71501"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/video.mp4"
},
{
"models": [
"IP4100",
"TVIP42561",
"TVIP92700"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/stream1"
},
{
"models": [
"IP4100",
"IPCS34511A"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/h264_stream"
},
{
"models": [
"IPCA 62520",
"IPCB42515A",
"IPCB62510A",
"TVIP61560"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/1"
},
{
"models": [
"IPCA 72500",
"IPCB42515A"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/s2"
},
{
"models": [
"IPCA53000",
"IPCB42510B",
"IPCB44510A",
"IPCB64515B"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/Streaming/Channels/102"
},
{
"models": [
"IPCB42550",
"IPCB78520",
"NVR10030",
"TVIP41500",
"TVIP52500"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/Streaming/Channels/101"
},
{
"models": [
"IPCB54611B",
"TVIP44510",
"TVIP68510"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/0"
},
{
"models": [
"IPCb64620",
"IPCB78520",
"IPCS84530",
"TVIP 21000",
"TVIP41500",
"TVIP60000",
"TVIP61500",
"TVIP61550",
"TVIP61560",
"TVIP62560"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/live.sdp"
},
{
"models": [
"IPCB7250",
"IPCB74520",
"IPCB74521",
"IPCB78520",
"TVIP22500",
"TVIP31001",
"TVIP31501",
"TVIP32500",
"TVIP60000",
"TVIP71501",
"TVIP72500"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/video.h264"
},
{
"models": [
"IPTV42560"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam[CHANNEL]/h264"
},
{
"models": [
"IPTV605550",
"TVIP41550"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/viewer/video.jpg?resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?loginuse=[USERNAME]&loginpas=[PASSWORD]"
},
{
"models": [
"Other",
"TVIP10000",
"TVIP20000",
"TVIP20050",
"TVIP21500",
"tvip21551"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/jpg/image"
},
{
"models": [
"Other",
"TVIP20000",
"TVIP21500",
"TVIP717551"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/view/image?pro_[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "cgi-bin/view.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"Other",
"PortCam",
"TV20550",
"TV21550",
"TV32500",
"TVIP10550",
"TVIP11560",
"TVIP20000",
"TVIP20550",
"TVIP21550",
"TVIP41500",
"TVIP41550",
"TVIP61500",
"TVIP71501"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "video.mp4"
},
{
"models": [
"TIVP 31550",
"TVIP10001",
"TVIP10051",
"TVIP10055",
"TVIP11551",
"TVIP21501",
"TVIP21550",
"TVIP40000",
"TVIP41550",
"TVIP51500",
"TVIP51550",
"TVIP71550"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.mjpg?q=30&fps=33&id=0.5"
},
{
"models": [
"TIVP41550"
],
"type": "JPEG",
"protocol": "http",
"port": 80,
"url": "/cgi-bin/viewer/video.jpg?resolution=320x240"
},
{
"models": [
"tv7203",
"TVIP41550"
],
"type": "JPEG",
"protocol": "http",
"port": 80,
"url": "/cgi-bin/viewer/video.jpg?resolution=640x480"
},
{
"models": [
"TVIP10055",
"tvip10055A",
"TVIP10055A"
],
"type": "JPEG",
"protocol": "http",
"port": 10001,
"url": "/jpg/image.jpg?size=3"
},
{
"models": [
"TVIP21000",
"tvip41560"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/ch0_0.h264"
},
{
"models": [
"TVIP21500"
],
"type": "MJPEG",
"protocol": "http",
"port": 80,
"url": "/video.mjpg"
},
{
"models": [
"TVIP22500",
"TVIP31001",
"TVIP32500",
"TVIP41560",
"TVIP62520"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "video.h264"
},
{
"models": [
"TVIP41500"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/11"
},
{
"models": [
"TVIP41500",
"TVIP41550_cam1",
"TVIP41550_cam2"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "VideoInput/[CHANNEL]/h264/1"
},
{
"models": [
"TVIP41550"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video[USERNAME].mjpg"
},
{
"models": [
"tvip41560",
"TVIP61550"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/Streaming/Channels/2"
},
{
"models": [
"TVIP62000",
"TVIP62500"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "jpeg/pull"
},
{
"models": [
"TVIP72000"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/VideoInput/0/h264/1"
},
{
"models": [
"TVIP82561"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/mpeg4/media.amp?resolution=640x480"
}
]
}
-28
View File
@@ -1,28 +0,0 @@
{
"brand": "Ac38xx",
"brand_id": "ac38xx",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"dm12",
"MD12"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/onvif/live/2"
},
{
"models": [
"DM12",
"MD12"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/onvif/live/1"
}
]
}
-36
View File
@@ -1,36 +0,0 @@
{
"brand": "Acam",
"brand_id": "acam",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"C2100"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/ONVIF/channel2"
},
{
"models": [
"imp2irmptz"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/user=[USERNAME]_password=[PASSWORD]_channel=1_stream=0.sdp"
},
{
"models": [
"n287z752",
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
}
]
}
-29
View File
@@ -1,29 +0,0 @@
{
"brand": "Accfly",
"brand_id": "accfly",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"c091wx",
"c102wx",
"c120wx",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 5544,
"url": "/11"
},
{
"models": [
"P72"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=2"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "Accsxperts",
"brand_id": "accsxperts",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"5deMayo"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]x[HEIGHT]"
}
]
}
-31
View File
@@ -1,31 +0,0 @@
{
"brand": "Ace",
"brand_id": "ace",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Esperanza",
"Other",
"samsung",
"Xin",
"Yca"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videofeed"
},
{
"models": [
"noname",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/profile0"
}
]
}
-123
View File
@@ -1,123 +0,0 @@
{
"brand": "Acer",
"brand_id": "acer",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"A100",
"A500",
"ASPIRE",
"LMT"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videofeed"
},
{
"models": [
"A500"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"A500",
"Apire One",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "image.jpg"
},
{
"models": [
"A500"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "current[CHANNEL].jpg"
},
{
"models": [
"A500"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "/control/faststream.jpg?stream=MxPEG&needlength&fps=6"
},
{
"models": [
"Apire One"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "Image.jpg"
},
{
"models": [
"Apire One",
"Aspire"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "out.jpg?id=0.5"
},
{
"models": [
"Aspire"
],
"type": "MJPEG",
"protocol": "http",
"port": 8090,
"url": "/video.mjpg"
},
{
"models": [
"ASPIRE"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"Iconia",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "shot.jpg"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/cam/realmonitor"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "Aceri-bcn",
"brand_id": "aceri-bcn",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/video.cgi?msubmenu=mjpg"
}
]
}
-90
View File
@@ -1,90 +0,0 @@
{
"brand": "Acesee",
"brand_id": "acesee",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"AC04",
"AVZM40P130",
"DSE",
"EB225/SH",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/Streaming/Channels/1"
},
{
"models": [
"acdsee",
"ST-316-2M-AI"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/h264_stream"
},
{
"models": [
"AMB36HL200W"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 8061,
"url": "/2"
},
{
"models": [
"AVP40P200",
"Dome",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/0"
},
{
"models": [
"AVTN40P130",
"avzm40p200",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snap.jpg?JpegCam=[CHANNEL]"
},
{
"models": [
"AVZM40P130"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "ipcam/avc.cgi?audiostream=[CHANNEL]"
},
{
"models": [
"K9604-W",
"ST-316-2M-AI"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "cgi-bin/view.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
}
]
}
-56
View File
@@ -1,56 +0,0 @@
{
"brand": "Achtertuin",
"brand_id": "achtertuin",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"3011",
"N3011"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/cam1/onvif-h264"
},
{
"models": [
"3011",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.cgi?resolution=VGA"
},
{
"models": [
"Hooldoor",
"huawau"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 5544,
"url": "/11"
},
{
"models": [
"Link"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.cgi?resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Panasonic"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "nphMotionJpeg?Resolution=640x480&Quality=Standard"
}
]
}
-18
View File
@@ -1,18 +0,0 @@
{
"brand": "Acm-v3002",
"brand_id": "acm-v3002",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Fine",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/stream2"
}
]
}
-62
View File
@@ -1,62 +0,0 @@
{
"brand": "Acm",
"brand_id": "acm",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"1311"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/encoder?USER=[USERNAME]&PWD=[PASSWORD]&SNAPSHOT"
},
{
"models": [
"4100b"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": ""
},
{
"models": [
"m101"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"m101"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.jpg?user=[USERNAME]&pwd=[PASSWORD]&strm=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi/mjpg/mjpeg.cgi"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "Acor",
"brand_id": "acor",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "cgi-bin/view.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
}
]
}
-182
View File
@@ -1,182 +0,0 @@
{
"brand": "Acromedia",
"brand_id": "acromedia",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"009",
"ACROMEDIA IN-009",
"IN/EX",
"IN/EX Series",
"IN-010",
"IN-09",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 10554,
"url": "tmpfs/auto.jpg"
},
{
"models": [
"009",
"Acromedia IN-009",
"ACROMEDIA IN-009",
"BLW-2004E-AHD",
"IN-010",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/11"
},
{
"models": [
"BLW-2004E-AHD"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"ECESMS",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"in/ex",
"IN/EX Series",
"IN-010",
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"IN/EX",
"IN/EX Series"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?rate=11"
},
{
"models": [
"IN/EX Series",
"IN/EX SERİES",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi"
},
{
"models": [
"in-009",
"IN-010",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/12"
},
{
"models": [
"IN-009",
"IN-010"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snap.jpg?JpegCam=[CHANNEL]"
},
{
"models": [
"IN-010"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?usr=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"IN-010"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/ONVIF/channel2"
},
{
"models": [
"IN-010"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&password=[PASSWORD]"
},
{
"models": [
"IN-010"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "ipcam/avc.cgi?audiostream=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam1/mpeg4"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "MediaInput/mpeg4"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.jpg"
}
]
}
-727
View File
@@ -1,727 +0,0 @@
{
"brand": "Acti",
"brand_id": "acti",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"000",
"00217",
"1231",
"1239",
"3411",
"3511",
"4200",
"4201",
"5711n",
"7411 B",
"7911",
"8201",
"A41",
"A71",
"acd 2200",
"ACD2000",
"ACD2100",
"ACM-1011",
"ACM11231",
"ACM1231",
"ACM-1431",
"ACM-1431N",
"acm-1431P",
"ACM-1432P",
"acm3001",
"ACM-3001",
"ACM3011",
"ACM-3211",
"ACM3401",
"ACM-3411",
"ACM-3511",
"ACM3601",
"ACM-3601",
"ACM3701",
"acm-4000",
"acm4001",
"ACM-4001",
"ACM-4100",
"ACM-4200",
"acm4201",
"ACM-4201",
"ACM-5001",
"ACM-5601",
"acm-5611",
"ACM5611",
"ACM-7411",
"acm-7511",
"acm8201",
"ACM-8211",
"ACM-8511",
"ACN-3211",
"acti d55",
"ACTI IP CAMERA",
"ACTI-1231",
"ACTiMyView",
"ADC3011",
"B21",
"B27",
"B410",
"B45",
"b53",
"B77A",
"b97",
"D11",
"D12",
"D31",
"D32",
"D51",
"D52",
"D55",
"d61a",
"D64",
"d71a",
"D72",
"D72A",
"D82",
"D92",
"E 913",
"E12",
"E12A",
"E13",
"E22VA",
"E31",
"E32",
"E32A",
"E33",
"E36",
"e37",
"E41",
"E42",
"E42A",
"E43",
"e43b",
"E44A",
"E45A",
"E46",
"E51 Manual",
"E53",
"e56",
"E61",
"E62A",
"E66",
"E72A",
"E77",
"E77--A-XX-14E-00179",
"E77-Phil",
"E816",
"E82",
"E91",
"E92",
"E93",
"E94",
"e97",
"E98",
"I51",
"I96",
"i98",
"KCM-3311",
"KCM-3911",
"KCM-5211",
"KCM5511",
"KCM5611",
"KCM-5611",
"KCM7111",
"Other",
"SED-2120",
"SHS",
"TCM 4301",
"TCM 4511",
"TCM-1111",
"TCM1231",
"TCM-1511",
"TCM3041",
"TCM-3111",
"TCM3401",
"TCM3411",
"TCM-3511",
"TCM-4101",
"TCM-4201",
"TCM4301-09C-X",
"tcm-4511",
"TCM5311",
"TCM5611",
"TCM7411",
"tcm-7811"
],
"type": "JPEG",
"protocol": "http",
"port": 7070,
"url": "cgi-bin/encoder?USER=[USERNAME]&PWD=[PASSWORD]&SNAPSHOT"
},
{
"models": [
"000",
"7411 B",
"acm 8511",
"ACM3601",
"acm4201",
"ACM-4201",
"ACM-7411",
"ACM-8211",
"acti d55",
"D52",
"D55",
"d61a",
"D92",
"Dome",
"E54",
"E77",
"KCM-5211",
"TCM1231",
"TCM-1231",
"tcm-4511"
],
"type": "JPEG",
"protocol": "http",
"port": 80,
"url": "/cgi-bin/encoder?USER=[USERNAME]&PWD=[PASSWORD]&SNAPSHOT"
},
{
"models": [
"1231",
"3411",
"A41",
"A416",
"ACD2100",
"ACM-1231",
"ACM-1431N",
"ACM3211",
"ACM-3401",
"ACM-3511",
"ACM-4001",
"ACM-4201",
"ACM-7411",
"b53",
"B54",
"B910",
"B95--A2XX-14B-00310",
"d11",
"D12",
"D21",
"D31",
"D32",
"D42",
"D51",
"D52",
"D55",
"D72",
"D82",
"D92",
"DO4M36A",
"E12",
"E13",
"E32",
"E33",
"E33 chan2",
"E42A",
"E43",
"E43A",
"E46",
"E51",
"E52",
"E53",
"E53--A-XX-13G-00029",
"e617",
"E63",
"E65",
"E73",
"E73A-A-XX-15C-00034",
"E76",
"E77",
"E81",
"E82",
"E84",
"E86a",
"E91",
"E96",
"I42",
"I51",
"KCM-3311",
"KCM-3911",
"KCM-5611",
"KCM7211",
"KCM7911",
"KCM8211",
"Other",
"v24",
"Z31",
"Z34",
"Z82",
"z95"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/stream1"
},
{
"models": [
"1231",
"1511",
"4200",
"ACCA",
"ACD2100",
"ACM 5711",
"ACM-1011",
"acm1231",
"acm1431",
"ACM-1511",
"acm3001",
"ACM-3001",
"ACM3211",
"ACM-3311",
"ACM-3401",
"ACM-3411",
"ACM-3511",
"ACM3601",
"ACM-4001",
"ACM-4200",
"ACM-4201",
"ACM-5601",
"ACM-7411",
"ACM-8511",
"ACTI IP CAMERA",
"B41",
"B45",
"B87",
"d11",
"d31",
"D32",
"d51",
"D64",
"d72",
"D82A",
"E12",
"E12A",
"E14",
"E22",
"E271",
"E33 chan2",
"E37",
"E441A",
"E61",
"E66",
"E77",
"E77--A-XX-14E-00179",
"E91",
"E92",
"E93",
"E96",
"E97",
"E98",
"KCM-5611",
"KCM7211",
"kcm-8111",
"Other",
"TCM 4511",
"TCM3011",
"TCM-4201",
"TCM-5111",
"TCM5311",
"TCM5311MG",
"tcm-7811"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/cmd/system?GET_STREAM&USER=[USERNAME]&PWD=[PASSWORD]"
},
{
"models": [
"1231",
"3411",
"4201",
"ACM-1011",
"ACM1231",
"ACM1231 egen",
"ACM-3401",
"ACM-3511",
"ACM-4001",
"ACM-4201",
"acm-5601",
"ACM5611",
"B87",
"d11",
"D12",
"D21",
"d31",
"D51",
"D52",
"D55",
"D72",
"E12",
"E32",
"E33 chan2",
"E46",
"E73",
"E77",
"E91",
"i94",
"KCM-5611",
"KCM7211",
"KCM7311",
"Other",
"TCM 3511",
"TCM 4511",
"TCM1231",
"TCM3111",
"TCM-4201",
"TCM5111"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": ""
},
{
"models": [
"1231",
"22VA",
"A41",
"ACM-1231",
"ACM3211",
"ACM3411",
"ACM-5001",
"ACM5611",
"B55",
"B67",
"B71",
"B95",
"B95--A2XX-14B-00310",
"B97--A-XX-13L-00049",
"d32",
"D32--A-XX-13K-00022",
"D54",
"D55",
"D71A",
"D71--A-XX-13C-00408",
"D81A-A-XX-15E-0",
"D91",
"E11",
"E12",
"E12A",
"E13A",
"E16",
"E22VA",
"E31",
"E32A",
"E43B",
"e46",
"E46",
"E63A",
"E77",
"E77--A-XX-14F-00933",
"E81",
"E816",
"I51",
"I71",
"i910",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 7070,
"url": "/onvif-stream1"
},
{
"models": [
"1231",
"7401",
"acm1231",
"ACM-1231",
"acm4201",
"ACM-4201",
"ACM-5001",
"ACM-7411",
"B71",
"E44",
"I47",
"TCM 4301"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/cgi-bin/cmd/system?GET_STREAM&USER=[USERNAME]&PWD=[PASSWORD]"
},
{
"models": [
"168",
"7911",
"A82",
"A84",
"a94",
"ACM-1231",
"ACM-3511",
"ACM-7411",
"ACTI IP CAMERA",
"B410",
"B43",
"b45",
"B81",
"B83",
"d11",
"D32",
"E12",
"E13A",
"E15",
"e21",
"E22VA",
"E32",
"E33",
"E33A",
"E34",
"E415",
"E42A",
"E51",
"E74A",
"E77",
"E79",
"E81",
"E86A",
"E95",
"EQ1",
"GCO",
"KCM-5311",
"KCM7311",
"KCM8211",
"Other",
"SED-2120",
"TCM 4511",
"TCM-1111",
"TCM1231",
"TCM-1231",
"TCM3111",
"TCM-3511",
"tcm-6630",
"TCM-7411"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 7070,
"url": "/"
},
{
"models": [
"A81",
"ACM3601",
"ACM-3601"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 7070,
"url": "/onvif-media/media.amp"
},
{
"models": [
"ACM-1431",
"ACM-3401",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "jpg/image.jpg"
},
{
"models": [
"ACM-3511"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam[CHANNEL]/h264"
},
{
"models": [
"ACM-3511",
"ACM-4001",
"ACM-4200"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "h264"
},
{
"models": [
"ACM-4001",
"ACTi B97",
"B96",
"B97",
"E11",
"E73--A-XX-13G-00002",
"E73--A-XX-13I-00238"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/stream2"
},
{
"models": [
"ACM-4001",
"D31",
"D82a",
"e925",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 7070,
"url": "/onvif&event&video2"
},
{
"models": [
"ACM-4201",
"TCM-1231"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "mjpeg.cgi?user=[USERNAME]&password=[PASSWORD]&channel=[CHANNEL]"
},
{
"models": [
"ACM-5001",
"ACM-7411",
"ACTi I25",
"b53",
"d10",
"D22VA",
"D61",
"E32A",
"E67a",
"E77",
"e925",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 7070,
"url": "/onvif&event&video1"
},
{
"models": [
"ACM-5001"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 7070,
"url": "/cgi-bin/cmd/encoder?GET_STREAM"
},
{
"models": [
"acm-5611",
"D61",
"d61a",
"E93"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/cgi-bin/encoder?USER=[USERNAME]&PWD=[PASSWORD]&GET_STREAM"
},
{
"models": [
"ACM5611",
"b71",
"B95",
"BS30",
"d32-2",
"E53--A-XX-14C-00157",
"E77",
"E77--A-XX-14E-00179",
"I96--A-XX-13K-00077"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/onvif-stream2"
},
{
"models": [
"ACTi B81",
"d82a",
"E413",
"I96"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 7070,
"url": "/onvif&event&audio&video1"
},
{
"models": [
"av3100ai",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "image?res=half&x0=0&y0=0&x1=1600&y1=1200&quality=15&doublescan=0&ssn=1340443365044&id=1340443379230"
},
{
"models": [
"D12"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/view/image?pro_[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi/jpg/image.cgi"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "now.jpg"
},
{
"models": [
"SRICAM"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Z34"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam0/h264"
}
]
}
-72
View File
@@ -1,72 +0,0 @@
{
"brand": "Action",
"brand_id": "action",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"000",
"b53"
],
"type": "JPEG",
"protocol": "http",
"port": 7070,
"url": "cgi-bin/encoder?USER=[USERNAME]&PWD=[PASSWORD]&SNAPSHOT"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/live/av0"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "rtsp",
"port": 0,
"url": "cam[CHANNEL]/mjpeg"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videofeed"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "cgi-bin/net_video.cgi?channel=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "ch0_0.h264"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam[CHANNEL]/h264"
}
]
}
-44
View File
@@ -1,44 +0,0 @@
{
"brand": "Actioncam",
"brand_id": "actioncam",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"cam300"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=3"
},
{
"models": [
"camm"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"IPM"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "[CHANNEL]/video.cgi"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/guest/Video.cgi?media=JPEG"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "Actiontec",
"brand_id": "actiontec",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"rc8021v"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "img/video.asf"
}
]
}
-28
View File
@@ -1,28 +0,0 @@
{
"brand": "Activa",
"brand_id": "activa",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"ACT-200W",
"ACT-2800/3100"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi/mjpg/mjpg.cgi"
},
{
"models": [
"ACT-2100",
"ACT-2800/3100"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi/jpg/image.cgi"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "Active Vision",
"brand_id": "active-vision",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"ACC-V11"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "GetData.cgi"
}
]
}
-161
View File
@@ -1,161 +0,0 @@
{
"brand": "Active",
"brand_id": "active",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/streaming/video0"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "mpeg4/media.amp?resolution=640x480"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?usr=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/guest/Video.cgi?media=JPEG&channel=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/guest/Video.cgi?media=JPEG"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "axis-cgi/mjpg/video.cgi"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "axis-cgi/mjpg/video.cgi?date=1&clock=1&camera=[CHANNEL]&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "axis-cgi/mjpg/video.cgi?camera=[CHANNEL]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "axis-cgi/mjpg/video.cgi?date=1&clock=1&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "axis-cgi/mjpg/video.cgi?camera=1&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "ch0_0.h264"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "live"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "capture[CHANNEL].jpg"
},
{
"models": [
"SC530"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.jpg?user=[USERNAME]&pwd=[PASSWORD]&strm=[CHANNEL]"
},
{
"models": [
"SC530"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "mjpeg"
},
{
"models": [
"Vision SX-1200"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "GetData.cgi?CH=[CHANNEL]&Codec=jpeg&Size=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Vision SX-500"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "[USERNAME]/cam[CHANNEL].jpg"
}
]
}
-36
View File
@@ -1,36 +0,0 @@
{
"brand": "Activecam",
"brand_id": "activecam",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"ac-d4121ir1v2"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/h264"
},
{
"models": [
"AC-D7111IR1",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/streaming/video0"
},
{
"models": [
"AC-D7111IR1"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/streaming/video1"
}
]
}
-49
View File
@@ -1,49 +0,0 @@
{
"brand": "Acumen",
"brand_id": "acumen",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"AiP-B24N",
"AiP-B34",
"AiP-M53",
"Other",
"Y04"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/rtsph2641080p"
},
{
"models": [
"AIS-S22H-B1Y0W"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/user=[USERNAME]_password=[PASSWORD]_channel=1_stream=1.sdp"
},
{
"models": [
"ekran",
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "mpg4/rtsp.amp"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]x[HEIGHT]"
}
]
}
-26
View File
@@ -1,26 +0,0 @@
{
"brand": "Acunico",
"brand_id": "acunico",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?loginuse=[USERNAME]&loginpas=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/ucast/11"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "Acvil",
"brand_id": "acvil",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"WIFI-5MP-30"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/Streaming/channels/702"
}
]
}
-26
View File
@@ -1,26 +0,0 @@
{
"brand": "Adamas",
"brand_id": "adamas",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"wnc-01"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "tmpfs/auto.jpg"
},
{
"models": [
"wnc-01"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snap.jpg?JpegCam=[CHANNEL]"
}
]
}
-26
View File
@@ -1,26 +0,0 @@
{
"brand": "Adapter",
"brand_id": "adapter",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"dvr"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?loginuse=[USERNAME]&loginpas=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf"
}
]
}
-67
View File
@@ -1,67 +0,0 @@
{
"brand": "Adata",
"brand_id": "adata",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"1MP HD P2P CAMERA"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/live/ch0"
},
{
"models": [
"AMB",
"AMB-MD",
"APOIP-MB",
"BLC02",
"EYE1.3",
"EYE2MBS",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/cam/realmonitor"
},
{
"models": [
"AMB",
"AMB-MB1.3",
"apollo hd dvr",
"EYE1.3",
"EYE2MBS",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?loginuse=[USERNAME]&loginpas=[PASSWORD]"
},
{
"models": [
"APOIP-MB",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"APOIP-MB",
"BCC",
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": ""
}
]
}
-130
View File
@@ -1,130 +0,0 @@
{
"brand": "Adc",
"brand_id": "adc",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"700x",
"723",
"V510",
"v520ir",
"V520IR",
"V521IR",
"V721W",
"V820"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 1026,
"url": "/live.sdp"
},
{
"models": [
"700X"
],
"type": "JPEG",
"protocol": "http",
"port": 1026,
"url": "cgi-bin/viewer/video.jpg?resolution=640x480"
},
{
"models": [
"723",
"ADCi400-X002",
"D064",
"Ilustra400",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/live1.sdp"
},
{
"models": [
"723",
"Other",
"V520IR",
"V820"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/live2.sdp"
},
{
"models": [
"ILLustra400",
"ILUSTRA400"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "dms"
},
{
"models": [
"ILLustra400",
"ILUSTRA400"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "image/jpeg.cgi"
},
{
"models": [
"Other",
"V520IR",
"V723"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.mjpg"
},
{
"models": [
"Other",
"v510",
"V520IR",
"V720W",
"V721W"
],
"type": "JPEG",
"protocol": "http",
"port": 1026,
"url": "cgi-bin/viewer/video.jpg"
},
{
"models": [
"V510"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/viewer/video.jpg?channel=[CHANNEL]&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"V520IR",
"V721W"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 1032,
"url": "/live3.sdp"
},
{
"models": [
"V521IR"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/11"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "Adeco",
"brand_id": "adeco",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"PTZ"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 5544,
"url": "/11"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "Adhua Dh-ipc-hdw4233c-a",
"brand_id": "adhua-dh-ipc-hdw4233c-a",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"DH-IPC-HDW4233C-A"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?1"
}
]
}
-116
View File
@@ -1,116 +0,0 @@
{
"brand": "Adhua",
"brand_id": "adhua",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"DH-HAC-HFW1200RMN-0360B-S3",
"DH-IPC-HDW4233C-A",
"HDB4300F-PT",
"MYCAM",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"DH-HAC-HFW1200RMN-0360B-S3",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?loginuse=[USERNAME]&loginpas=[PASSWORD]"
},
{
"models": [
"DH-IPC-HDW4233C-A"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/live0.264"
},
{
"models": [
"HDB4300F-PT"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "tmpfs/auto.jpg"
},
{
"models": [
"HDB4300F-PT",
"MyCam",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "axis-cgi/mjpg/video.cgi"
},
{
"models": [
"IPC-D1B20"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/cam/realmonitor?channel=1&subtype=00&authbasic=[AUTH]"
},
{
"models": [
"IPC-HDW1230S"
],
"type": "JPEG",
"protocol": "http",
"port": 80,
"url": "/cgi-bin/snapshot.cgi?loginuse=[USERNAME]&loginpas=htd%402Tg25"
},
{
"models": [
"IPC-HFW1320S-W",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?1"
},
{
"models": [
"N84CL52",
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/11"
},
{
"models": [
"xvr4808"
],
"type": "JPEG",
"protocol": "http",
"port": 80,
"url": "/cgi-bin/snapshot.cgi?chn=8&u=[USERNAME]&p=[PASSWORD]"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "Adiance",
"brand_id": "adiance",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "image.cgi?type=motion"
}
]
}
-62
View File
@@ -1,62 +0,0 @@
{
"brand": "Adj",
"brand_id": "adj",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"700-00048"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 1024,
"url": "/Streaming/Channels/1"
},
{
"models": [
"DVR (Channel 1)"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=1&subtype=0"
},
{
"models": [
"DVR (Channel 2)"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=2&subtype=0"
},
{
"models": [
"DVR (Channel 3)"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=3&subtype=0"
},
{
"models": [
"Wireless IPCAM"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&password=[PASSWORD]"
},
{
"models": [
"WIRELESS IPCAM"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.jpg?user=[USERNAME]&pwd=[PASSWORD]"
}
]
}
-433
View File
@@ -1,433 +0,0 @@
{
"brand": "Adt",
"brand_id": "adt",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"0c810",
"0C810",
"1000",
"1600hd",
"8025b",
"A-ADT-4HS2",
"AD412-ADT",
"ADT8025B",
"G-Camera",
"i1000",
"ICAMERA",
"icamera 1000",
"Icamera 1000",
"ICAMERA1000",
"ICAMERA-1000-ADT",
"MDC83",
"NV412A-ADT",
"OC810",
"OC810-ADT",
"OC835-ADT",
"Other",
"PULSE",
"RC8010",
"RC8021",
"RC8021W",
"RC8021W-ADT",
"RC8025",
"RC8025-ADT",
"rc8025b",
"Rc8025b",
"RC8025B-adt",
"RC8025B-ADT",
"RC8025B-V2",
"rc8-25b-adt",
"RCR021W-ADT",
"toycam"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "img/video.sav"
},
{
"models": [
"0c810",
"1000",
"8025B",
"ADT8025B",
"ICAMERA1000",
"ICAMERA-1000-ADT",
"MDC835-ADT",
"OC810",
"OC810-ADT",
"OC835-ADT",
"otc810",
"Other",
"pulsar",
"PULSE",
"RC8021",
"RC8021W",
"RC8021W-ADT",
"RC8025",
"RC8025-ADT",
"RC8025B",
"RC8025B-ADT",
"rc8325-v2"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi"
},
{
"models": [
"0C810",
"1234",
"8025",
"8025B",
"A-ADT4HS2",
"ADT8025B",
"Icamera 1000",
"ICamera1000",
"ICAMERA-1000",
"ICAMERA-1000-ADT",
"mdc835",
"NV412A",
"OC810",
"OC810-ADT",
"OC835-ADT",
"oc835v3",
"OTC810",
"Other",
"pulse",
"RC8010",
"RC8021",
"RC8021W",
"rc8021w-adt",
"RC8021W-ADT",
"RC8025",
"RC8025-ADT",
"RC8025b",
"RC8025B-adt",
"RC8025B-V2",
"RC8025b-vb",
"RC8201",
"rc8235",
"RC8326",
"RCR021W-ADT"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "img/video.mjpeg"
},
{
"models": [
"1600hd",
"A-ADT4HS2",
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam/realmonitor?channel=[CHANNEL]&subtype=1"
},
{
"models": [
"8025B",
"iCamera-1000",
"ICAMERA1000",
"OC810-ADT",
"RC8025-ADT",
"RC8025B-ADT"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?img=vga"
},
{
"models": [
"8025B",
"iCamera",
"Icamera 1000",
"ICAMERA1000",
"ICAMERA-1000-ADT",
"NV412A",
"OC810",
"OC810-ADT",
"Other",
"pulse",
"RC8021",
"RC8021W",
"RC8021W-ADT",
"RC8025",
"RC8025-ADT",
"RCR021W-ADT"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=2"
},
{
"models": [
"A-ADT4HS2",
"Icamera 1000",
"ICAMERA1000",
"ICamera-1000-ADT",
"oc810",
"OC810-ADT",
"Other",
"RC8021",
"RC8021W-ADT",
"RC8025",
"RC8025B-ADT"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "img/mjpeg.jpg"
},
{
"models": [
"A-ADT-4HS2"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "cam4/mpeg4"
},
{
"models": [
"AD412-ADT",
"nv412a",
"NV412A-ADT",
"RC8021",
"RC8021W",
"RC8021W-ADT"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "img/video.asf"
},
{
"models": [
"Digital Video Recorder"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=2&subtype=1"
},
{
"models": [
"DYK4500"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"DYK4500"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/net_jpeg.cgi?ch=[CHANNEL]"
},
{
"models": [
"G-CAMERA"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snap.jpg"
},
{
"models": [
"ICAMERA",
"ICAMERA 1000",
"ICAMERA-1000-ADT",
"OC810",
"Other",
"PULSE",
"RC8021W-ADT",
"RC8025-ADT",
"rc8025b",
"RC8025b-ADT"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi?size=3"
},
{
"models": [
"ICAMERA1000",
"ICAMERA-1000-ADT",
"ipcam-wo",
"OC810-ADT",
"Other",
"RC8021",
"RC8021W-ADT",
"rc8025",
"RC8025-ADT",
"RC8025B",
"RC8025B-ADT"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "img/mjpeg.cgi"
},
{
"models": [
"ICAMERA-1000",
"OC810-ADT",
"OC845",
"RC8025B-ADT"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/img/video.sav"
},
{
"models": [
"NV412a",
"RC8021W",
"rc8021w-adt"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/img/video.asf"
},
{
"models": [
"NV412A-ADT"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?1"
},
{
"models": [
"NV412A-ADT",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?loginuse=[USERNAME]&loginpas=[PASSWORD]"
},
{
"models": [
"NV412A-ADT",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/snapshot.cgi?chn=[CHANNEL]&u=[USERNAME]&p=[PASSWORD]"
},
{
"models": [
"OC810-ADT",
"rc8021w",
"sc468",
"SC87C51C"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/img/video.mjpeg"
},
{
"models": [
"oc835v3"
],
"type": "MJPEG",
"protocol": "http",
"port": 80,
"url": "/img/mjpeg.cgi"
},
{
"models": [
"oc845"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/11"
},
{
"models": [
"OC845"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam4/mpeg4"
},
{
"models": [
"OC845"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/user=[USERNAME]_password=[PASSWORD]_channel=1_stream=0.sdp"
},
{
"models": [
"rc8021w"
],
"type": "MJPEG",
"protocol": "http",
"port": 80,
"url": "/img/main.cgi?"
},
{
"models": [
"RC8021W"
],
"type": "MJPEG",
"protocol": "http",
"port": 81,
"url": "videostream.cgi?rate=0&user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"rc8021w-adt"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/img/mjpeg.jpg"
},
{
"models": [
"RC8025B-ADT"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=0&subtype=1"
},
{
"models": [
"SC821C83"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/img/main.cgi?next_file=main.htm"
}
]
}
-18
View File
@@ -1,18 +0,0 @@
{
"brand": "Adv",
"brand_id": "adv",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"adv1",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videofeed"
}
]
}
-220
View File
@@ -1,220 +0,0 @@
{
"brand": "Advance",
"brand_id": "advance",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"002fvwu",
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"HVC",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]&count=0"
},
{
"models": [
"NetCam"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"NetCam"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"NetCam"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=320x240"
},
{
"models": [
"NetCam"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/videostream.cgi"
},
{
"models": [
"NetCam"
],
"type": "FFMPEG",
"protocol": "http",
"port": 82,
"url": "/videostream.asf?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"NetCam",
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf"
},
{
"models": [
"NetCam"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/"
},
{
"models": [
"Other",
"WB-IP03A"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=[WIDTH]x[HEIGHT]"
},
{
"models": [
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "ch0_0.h264"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "tmpfs/auto.jpg"
},
{
"models": [
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "snapshot.cgi?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/sf.cgi"
},
{
"models": [
"Other"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "img/video.mjpeg"
},
{
"models": [
"WB-IP03A",
"wp00030A"
],
"type": "FFMPEG",
"protocol": "http",
"port": 80,
"url": "/video.cgi?resolution=VGA"
},
{
"models": [
"WB-IP03A"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?resolution=8&rate=13"
},
{
"models": [
"WB-IP03A"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video.cgi?resolution=VGA"
},
{
"models": [
"WB-IP03A"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?rate=11"
},
{
"models": [
"WB-IP03A"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?rate=0"
},
{
"models": [
"WB-IP03A"
],
"type": "VLC",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]"
},
{
"models": [
"WB-IP03A"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
}
]
}
-80
View File
@@ -1,80 +0,0 @@
{
"brand": "Advanced Home",
"brand_id": "advanced-home",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"elro"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "image.jpg"
},
{
"models": [
"ELRO"
],
"type": "FFMPEG",
"protocol": "http",
"port": 0,
"url": "videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"icam"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "axis-cgi/mjpg/video.cgi"
},
{
"models": [
"lc-1140"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0"
},
{
"models": [
"Other"
],
"type": "FFMPEG",
"protocol": "http",
"port": 8081,
"url": "/videostream.asf?user=[USERNAME]&pwd=[PASSWORD]&resolution=64&rate=0"
},
{
"models": [
"Phone"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "video?submenu=mjpg"
},
{
"models": [
"RC8025B-ADT"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "img/snapshot.cgi"
},
{
"models": [
"S4X"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "mjpeg"
}
]
}
-327
View File
@@ -1,327 +0,0 @@
{
"brand": "Advidia",
"brand_id": "advidia",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"A14",
"A-15",
"A-30",
"A-34W",
"A-38-F",
"A-44-IR",
"A-49-F",
"A-54-OD",
"Other",
"vp-16"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/Streaming/Channels/1"
},
{
"models": [
"A14",
"A-34"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "MediaInput/mpeg4"
},
{
"models": [
"A-14",
"A-34W",
"A-45",
"A-46"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "ch0_0.h264"
},
{
"models": [
"A-28",
"a-35",
"vp-4"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/ch0_0.h264"
},
{
"models": [
"A-34W",
"A-37FW",
"A-47",
"M-46-FW",
"VP-16-V2"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/Streaming/Channels/101"
},
{
"models": [
"A-34W",
"A-37FW",
"A-44-IR",
"A-45"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "live/mpeg4"
},
{
"models": [
"a-35",
"A-55",
"vp-16"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/Streaming/Channels/103"
},
{
"models": [
"A-37fw",
"A-37-FW",
"A-47",
"Other"
],
"type": "VLC",
"protocol": "rtsp",
"port": 0,
"url": "video.mp4"
},
{
"models": [
"A-427-V",
"vp-4",
"VP-8"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/MediaInput/mpeg4"
},
{
"models": [
"A-427-V",
"VP-16-V2"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/Streaming/channels/901"
},
{
"models": [
"A-427-V",
"vp-8"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=2&subtype=00&authbasic=[AUTH]"
},
{
"models": [
"A-44-IR",
"a-49-f",
"VP-16"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/live/mpeg4"
},
{
"models": [
"a-49-f"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/video.mp4"
},
{
"models": [
"a-49-f",
"E-47-V"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=1&subtype=00&authbasic=[AUTH]"
},
{
"models": [
"A-54-OD"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/0"
},
{
"models": [
"A-65",
"B-38-V"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/stream1"
},
{
"models": [
"A-88-V",
"B-31"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/"
},
{
"models": [
"B-31"
],
"type": "VLC",
"protocol": "rtsp",
"port": 7070,
"url": ""
},
{
"models": [
"B-31"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/cmd/system?GET_STREAM&USER=[USERNAME]&PWD=[PASSWORD]"
},
{
"models": [
"B-31",
"B-33",
"B5360",
"Other"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "cgi-bin/encoder?USER=[USERNAME]&PWD=[PASSWORD]&SNAPSHOT"
},
{
"models": [
"E-37-V"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "axis-cgi/mjpg/video.cgi"
},
{
"models": [
"p-25",
"vp-8"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 0,
"url": "/ONVIF/MediaInput"
},
{
"models": [
"vp-16"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/Streaming/Channels/2"
},
{
"models": [
"vp-16"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 10554,
"url": "/Streaming/Channels/1103"
},
{
"models": [
"VP-16"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/Streaming/channels/902"
},
{
"models": [
"VP-16-V2"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/ch2_0.h264"
},
{
"models": [
"vp-8"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "//Streaming/Channels/2"
},
{
"models": [
"vp-8"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "//Streaming/Channels/5"
},
{
"models": [
"vp-8"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=3&subtype=00&authbasic=[AUTH]"
},
{
"models": [
"vp-8"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "/cam/realmonitor?channel=101&subtype=00&authbasic=[AUTH]"
},
{
"models": [
"VP-8"
],
"type": "FFMPEG",
"protocol": "rtsp",
"port": 554,
"url": "//Streaming/Channels/1"
}
]
}
-28
View File
@@ -1,28 +0,0 @@
{
"brand": "Advisen",
"brand_id": "advisen",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"123281"
],
"type": "JPEG",
"protocol": "http",
"port": 80,
"url": "/tmpfs/auto.jpg"
},
{
"models": [
"Other",
"UNLISTED",
"Visia 7"
],
"type": "JPEG",
"protocol": "http",
"port": 0,
"url": "tmpfs/auto.jpg"
}
]
}
-17
View File
@@ -1,17 +0,0 @@
{
"brand": "Advitronics",
"brand_id": "advitronics",
"last_updated": "2025-10-17",
"source": "ispyconnect.com",
"entries": [
{
"models": [
"PortaVision SIP"
],
"type": "MJPEG",
"protocol": "http",
"port": 0,
"url": "?action=stream"
}
]
}

Some files were not shown because too many files have changed in this diff Show More