Commit Graph

27698 Commits

Author SHA1 Message Date
Isaac Connor
e1aab1160e Bump version to 1.39.5 2026-04-08 22:53:39 -04:00
Isaac Connor
1f84c57ccc fix: use READ COMMITTED in Refresh_Summaries_SWR to avoid Events deadlock
INSERT INTO Event_Summaries_New SELECT * FROM VIEW_Event_Summaries took
shared next-key locks on the source Events table (required for STATEMENT
binlog correctness under the default REPEATABLE READ).  Concurrent DELETE
FROM Events deadlocked against those S locks.

Switch the procedure to READ COMMITTED so the source-side SELECT runs as
a consistent snapshot read with no row locks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:29:35 -04:00
Isaac Connor
73c1ebefb7 fix: rename migration to 1.39.5 and use MySQL-compatible index DDL
The 1.37.78 update slot is already taken on master by the User Roles
feature, so move the views migration to the next free slot, 1.39.5.

CREATE INDEX IF NOT EXISTS / DROP INDEX IF EXISTS in views.sql are
MariaDB-only and fail to parse on MySQL.  Replace both with the
INFORMATION_SCHEMA.STATISTICS conditional pattern used throughout the
ZoneMinder update scripts.

Also tighten the migration script to drop the SWR procedure, scheduled
event, and any prior view-named objects before sourcing views.sql, so
re-running on a partially-migrated database is safe.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:29:22 -04:00
Ben Dailey
a87e2d03a5 feat: replace Event_Summaries view with SWR snapshot table
Replace the Event_Summaries view with a physical snapshot table
refreshed via Stale-While-Revalidate (SWR) pattern. A stored
procedure (Refresh_Summaries_SWR) uses GET_LOCK for non-blocking
concurrency and atomic table rename for zero-downtime refresh.

Database changes (db/views.sql):
- Rename Event_Summaries view to VIEW_Event_Summaries (source view)
- Add Event_Summaries snapshot table and Event_Summaries_Metadata table
- Add Refresh_Summaries_SWR stored procedure with GET_LOCK and
  atomic rename pattern to prevent thundering herd
- Add MySQL EVENT for background refresh every 600 seconds

PHP call sites (web/):
- Add ensureSummariesFresh() helper in database.php with static
  per-request dedup and 60s staleness check
- Call ensureSummariesFresh() before Event_Summaries queries in
  console.php, _monitor_filters.php, and Monitor.php
- Add beforeFind() hook in CakePHP Event_Summary model

Perl call sites (scripts/):
- Add ensureSummariesFresh() sub in Event_Summary.pm with
  per-process 60s rate-limiting
- Call ensureSummariesFresh() in Monitor.pm Event_Summary accessor

Upgrade path (db/zm_update-1.37.78.sql.in):
- Drop any prior Event_Summaries view or table before recreating

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-07 12:53:42 -04:00
Ben Dailey
4fe2103fcd Replace Events_Hour/Day/Week/Month/Archived and Event_Summaries tables with views
Remove denormalized event summary tables and their associated triggers,
replacing them with views that query the Events table directly. This
eliminates trigger maintenance overhead and periodic reconciliation in
zmaudit/zmstats, since the views compute stats on the fly.

- Remove trigger definitions for event summary table maintenance
- Remove event summary table inserts from zm_event.cpp
- Remove event count reconciliation queries from zmaudit.pl
- Remove DELETE-on-views calls from zmstats.pl (views filter by date inherently)
- Remove Event_Summaries DELETE from Monitor.php (can't delete from a view)
- Add db/views.sql with view definitions and covering index
- Add upgrade script zm_update-1.37.78.sql.in (drop triggers, drop tables, create views)
- Update zm_create.sql.in to use views instead of tables for fresh installs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-07 11:29:30 -04:00
Isaac Connor
df29fb7c70 Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-04-06 09:40:04 -04:00
Isaac Connor
252ac03b77 Move the delay calculation code to after we run the filter so that the time taken running the filter is included 2026-04-06 09:39:01 -04:00
Isaac Connor
d8f30811cf Rename last_action to last_reload as that is what it actually is 2026-04-06 09:38:52 -04:00
Isaac Connor
f112ead9dd Include ExecuteInterval in warning 2026-04-06 09:38:44 -04:00
Isaac Connor
4df52e6a41 Don't use Fatal when there is an error preparing the sql. handle PostSQLConditions being an empty array 2026-04-03 17:48:35 -04:00
Isaac Connor
c06dab727e Include ExecuteInterval in warning 2026-04-03 13:11:20 -04:00
Isaac Connor
82261c047e Use now instead of 0 when no last_ran so that elapsesd=0 on initial run, and we don't log a warning. 2026-04-03 11:54:03 -04:00
Isaac Connor
fcd925900b fix: redirect stdin/stdout/stderr to /dev/null instead of closing them
Bug 376 (2006) closed all FDs starting from 0 when daemonizing. This
caused FD reuse problems: libx264 writing to a reused stderr FD led to
memory corruption (fixed in child spawn by 66f11435b, but not in the
parent's run()). It also meant children inherited closed FDs 0-2, so
any Perl die/warn output was silently lost, making daemon crashes
impossible to diagnose.

Redirect 0-2 to /dev/null (standard daemon practice) and close only
FDs 3+ for inherited sockets/DB connections. Children now inherit valid
FDs that won't crash or corrupt on write.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 11:45:32 -04:00
Isaac Connor
0912fc62cf Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-04-03 11:00:08 -04:00
Isaac Connor
b141c9e18a Warn() -> Warning(). Fixes #4724 2026-04-03 11:00:01 -04:00
Isaac Connor
34949769b0 fix: add Warn() as exported alias for Warning() in Logger
Warn() is a natural shorthand that's easy to reach for. Its absence
caused a silent crash in zmfilter when Warn() resolved to Perl's
built-in warn(), which wrote to a closed stderr under zmdc and killed
the process.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:59:51 -04:00
Isaac Connor
33a2148c7c Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-04-02 14:17:21 -04:00
Isaac Connor
af33926aa3 fix: reset last_write_index in Pause to restore DECODING_ONDEMAND bootstrap
Pause() did not restore last_write_index to the sentinel value
(image_buffer_count). After a Pause/Play cycle, the DECODING_ONDEMAND
fallback condition (last_write_index == image_buffer_count) was dead,
making decoding depend entirely on hasViewers(). This created a timing
gap where the decoder skipped packets after Play before zms called
setLastViewed, causing the decoder to fall behind capture.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:45:08 -04:00
Isaac Connor
692b77b4da fix: guard against empty auth_relay producing double && in zms URLs
When auth is disabled or auth_relay is empty, appending '&'+auth_relay
produces a trailing '&' which results in double '&&' when the next
parameter is appended (e.g. ?monitor=2&&scale=41&mode=single).

Guard all 4 places in MonitorStream.js where auth_relay is concatenated
into URLs, consistent with EventStream.js which already guards this.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 12:27:56 -04:00
Isaac Connor
7c08e3157b Fix missing quotes 2026-03-31 09:28:54 -04:00
Isaac Connor
7638b291d5 Bump up ubuntu and python version for readthedocs 2026-03-30 16:38:11 -04:00
Isaac Connor
48dce0311e fix: guard against null websocket in VideoRTC.onopen
ondisconnect() nulls this.ws, but the WebSocket open event fires
asynchronously. If ondisconnect() runs between socket creation and
the open callback, onopen() hits a null this.ws when adding the
message listener. Add a null guard to bail out cleanly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 16:24:14 -04:00
Isaac Connor
873d2a4abb fix: use shoelace formula for zone threshold pixel-to-percent migration
The previous migration relied on Zones.Area to convert pixel thresholds
to percentages, but this column is often 0 (never populated by the C++
daemon which calculates polygon area at runtime). Replace the single
UPDATE with a cursor-based stored procedure that computes the polygon
area directly from percentage coordinates using the shoelace formula,
then derives the pixel area for accurate threshold conversion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 09:14:30 -04:00
Isaac Connor
1ec9c449b4 fix: null-check StorageId column in Monitor::Load to prevent segfault
dbrow[col] for StorageId can be NULL when the database column contains
a NULL value. Passing NULL to atoi causes a segfault in strtol.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 09:13:50 -04:00
Isaac Connor
df594cac62 Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-03-30 09:07:04 -04:00
Isaac Connor
96aff8cbac Upgrade bootstrap-table to 1.27.1 2026-03-29 11:25:18 -04:00
Isaac Connor
cf27243055 fix: add DTS backward jump detection in ffmpeg camera capture
The existing PTS backward jump check in FfmpegCamera::Capture() does not
catch cases where DTS jumps back significantly (e.g. stream restarts,
encoder resets) while PTS may remain unaffected. This causes the
VideoStore to spend minutes forcing DTS monotonicity on every packet via
the write_packet fixup path, flooding logs with warnings.

Add per-stream DTS tracking (mLastVideoDTS/mLastAudioDTS) and a backward
jump check mirroring the existing PTS check: if DTS jumps back more than
10 seconds, increment error_count and after 6 occurrences return -1 to
trigger capture reconnection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 09:52:00 -04:00
Isaac Connor
58968a8f90 fix: clamp user bandwidth before defining ZM_WEB_* constants
The bandwidth limiter in skin.php ran after config.php was included,
so the ZM_WEB_* constants were defined using the unclamped cookie
value. When no cookie existed and ZM_BANDWIDTH_DEFAULT was 'high',
a user with MaxBandwidth='medium' would get high bandwidth config
values despite the navbar showing medium.

Move the MaxBandwidth clamp before the config.php include so the
switch statement sees the correct value.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 16:45:46 -04:00
Isaac Connor
05cc6fcca7 chore: remove obsolete ZM_FILTER_EXECUTE_INTERVAL config option
Each filter now has its own ExecuteInterval column, making the global
ZM_FILTER_EXECUTE_INTERVAL unused. The DB row will be cleaned up
automatically by zmupdate.pl on the next upgrade.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 16:31:33 -04:00
Isaac Connor
04d28258db fix: use minimum per-filter delay instead of last filter's delay in zmfilter
The sleep delay was overwritten by each filter in the loop, so only the
last filter's timing controlled the sleep. Now tracks the minimum delay
across all filters so no filter oversleeps its ExecuteInterval.

Also removes the unused ZM_FILTER_EXECUTE_INTERVAL reference since each
filter has its own ExecuteInterval, and fixes the overdue warning to
check the unclamped filter_delay and include the filter name.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 16:17:35 -04:00
Isaac Connor
6fabbb6d75 fix: use prepare instead of prepare_cached in Filter::Execute
The SQL changes every cycle due to zmDiskPercent/zmDiskBlocks/zmSystemLoad
string substitution with live values, so prepare_cached never actually
returns a cached handle. Instead it leaks one cache entry per distinct
substituted value over the process lifetime.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 15:48:15 -04:00
Isaac Connor
62ef4014ad fix: clear accumulated state in Filter::Sql() before rebuilding
PostSQLConditions, HasDiskPercent, HasDiskBlocks, and HasSystemLoad were
set during Sql() term processing but never cleared between rebuilds.
Each Execute() cycle pushed duplicate ExistsInFileSystem terms onto the
PostSQLConditions array, causing it to grow unboundedly over the process
lifetime.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 15:47:01 -04:00
Isaac Connor
b2f353f4a2 Merge pull request #4714 from IgorA100/patch-536184
Fix: A finger-shaped pointer cursor for the hide/show password buttons (skin.css)
2026-03-27 09:25:16 -04:00
Isaac Connor
0e78b5a6c6 Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-03-26 17:20:23 -04:00
Isaac Connor
4603309e38 Include full path in warning when fail to cache bust 2026-03-26 17:20:20 -04:00
Isaac Connor
277eece633 Log the value when event_close_mode is unkown 2026-03-26 17:19:59 -04:00
Isaac Connor
2d34db3e4c fix: handle HTTP-to-HTTPS redirect in Reolink_HTTP login
Reolink cameras may return a 302 redirect from HTTP to HTTPS.
LWP::UserAgent does not follow redirects for POST requests, so the
login would fail. Detect the redirect, update protocol/host/port from
the Location header, disable SSL verification for self-signed camera
certs, and retry the POST to the HTTPS endpoint. Subsequent API calls
use the updated protocol.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 14:01:14 -04:00
Isaac Connor
8fe8141eb5 fix: prefer MJPEG over raw YUV in V4L2 AUTO palette selection
Move MJPEG/JPEG ahead of YUYV/UYVY in the preferred format arrays
for all color spaces. MJPEG uses far less USB bandwidth than raw YUV
while the decode cost is minimal (sw MJPEG decoder).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 14:01:14 -04:00
Isaac Connor
9adbed166e fix: add missing CLOSE_DURATION event close mode handling
- Add "duration" string mapping in constructor and DB loader — was
  silently falling back to CLOSE_IDLE
- Add CLOSE_DURATION handler in analysis logic: close event when
  duration >= section_length regardless of alarm state

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 14:01:14 -04:00
Isaac Connor
7a4269cc7d Merge pull request #4720 from IgorA100/patch-389827
Fix: When executing monitorChangeStreamChannel(), always write the new channel to the cookie and to monitorStream.currentChannelStream on Watch page
2026-03-23 06:40:35 -04:00
IgorA100
0998e9d766 When executing monitorChangeStreamChannel(), always write the new channel to the cookie and to monitorStream.currentChannelStream (watch.js).
This will allow "monitorStream.start()" to be executed correctly if the stream was stopped when the channel was switched.
2026-03-22 13:35:08 +03:00
Isaac Connor
fd8adee68c Merge pull request #4713 from IgorA100/patch-792734
Fix: Read from 'zmWatchMuted' cookies instead of 'zmWatchMute' on Watch page
2026-03-21 06:43:07 -04:00
Isaac Connor
16760f44b0 Merge pull request #4716 from IgorA100/patch-89150
Change the "Mute" icon in the volume slider based on the volume level, not just when the "muted" attribute changes (MonitorStream.js)
2026-03-21 06:42:25 -04:00
Isaac Connor
8970718f96 Merge pull request #4719 from IgorA100/patch-272289
Silent refresh bootstrapTable on Console page
2026-03-21 06:41:54 -04:00
IgorA100
a685759885 Don't use "scrollTo" because it doesn't work properly. (console.js) 2026-03-21 11:58:00 +03:00
IgorA100
ac6dbe4ed6 Silent refresh bootstrapTable on Console page (console.js)
- The table refresh message will not appear briefly. The table will not "flicker."
Scrolling will attempt to return to the position it was in before the refresh.
2026-03-20 23:35:59 +03:00
Isaac Connor
7b3b9c82ae Merge pull request #4718 from anton-vinogradov/10-seconds-section
Minimal section length from 30 to 10 seconds (change required) #4717
2026-03-19 14:28:54 -04:00
Anton Vinogradov
b703a6be91 wip 2026-03-19 19:29:04 +03:00
Anton Vinogradov
30d48f2ec7 wip 2026-03-19 19:26:59 +03:00
IgorA100
f04a9075cc When starting a stream on the Watch page, don't execute controlMute() (watch.js)
When starting a stream on the Watch page, don't execute controlMute(), as this will cause the icon to be displayed before the stream actually starts playing.
We'll just set the "muted" property for the stream.
We'll manage the icon later.
2026-03-19 10:39:29 +03:00