Commit Graph
29711 Commits
Author SHA1 Message Date
IgorA100 8d1a9054ec - On the Zone page, when changePlayer() is called, execute monitorStream.start() with a 200ms delay; otherwise, the preceding stop() call might not have enough time to complete properly.
- When calling `monitorStream.manageAvailablePlayers()`, now pass the candidate player as an argument instead of determining the player from stored cookies inside `manageAvailablePlayers()`. This is necessary because cookies could belong to either the Watch page or the Zone page.
- On the Zone page, load `hls.min.js` if Go2RTC or RTSP2Web is being used for the monitor.
- `monitorStream.setPlayer()` is now executed within `monitorStream.manageAvailablePlayers()`. Previously, `manageAvailablePlayers()` only handled the assignment of `monitorStream.player`.
- Added a new function, `this.setRTSP2WebType()`, to avoid code duplication. This ensures that `RTSP2WebType` is checked and set even if `setPlayer()` is not called on the page.
- Minor optimization regarding variable usage.
- If `hls.min.js` is not loaded, attempting to play via HLS will now trigger a "The HLS library is not loaded" warning in the browser console and initiate a stream restart. Previously, this would result in an error.
2026-10-17 20:54:57 +03:00
IgorA100 75fa7e2df0 Update Janus condition to include 'zone' view 2026-10-16 17:07:41 +03:00
IgorA100 e66029d73e Manage available players in MonitorStream 2026-10-16 17:04:09 +03:00
Isaac Connor 629b0bf25f Merge pull request #5296 from nabbi/fix/release-tag-env
fix-low: pass the release tag through env and fix packpack's checkvars
2026-10-16 09:28:59 -04:00
Isaac Connor b8f9e00249 Merge pull request #5291 from IgorA100/patch-331473
Fix: Refactor Janus handling in MonitorStream.js
2026-10-16 09:22:38 -04:00
IgorA100 9996e8967f Fix syntax error in MonitorStream.js 2026-10-16 13:09:18 +03:00
IgorA100 a266a82998 Refactor Janus handling in MonitorStream.js
- The `janus` variable is no longer global; it now belongs to `MonitorStream`.
- In the `Janus.init` callback, do not perform any actions if the monitor is in a stopping state or is already stopped.
- Check for the existence of the `destroy` method before calling `janus.destroy()`.
- Allow the Janus player to be selected in `this.selectPlayer` regardless of the `streamChannel` on the Montage page. This will not cause visual confusion, as the Montage page does not allow selecting a `streamChannel` (it uses the default one). 
However, if the default `streamChannel` is a secondary one and the default player is set to Janus, the Janus player would never be selected on the Montage page. I believe this is incorrect, as we should allow for more flexibility.
2026-10-16 13:05:33 +03:00
Isaac ConnorandClaude Opus 5.5 7603a7458f fix: read yes/no, true/false and on/off in config files as booleans in PHP and Perl
A boolean option set in zm.conf or conf.d wins over the Config table, and a
person editing a file writes yes or off rather than 1 or 0. The C++ daemons
now read those words (ConfigFileValue, 4d7609d36), but PHP and Perl took the
value as written, and a non-empty string is true in both. So
ZM_STRICT_VIDEO_CONFIG=off in conf.d left the option on in the web UI and the
Perl scripts while zmc turned it off.

Read a file value for a boolean option the same way in all three: yes, true
and on are 1; no, false and off are 0; anything else stays as written. Only
booleans are read this way, so a string option such as a title keeps "Yes".

PHP defines the file values as constants before it reads the Config table,
since it needs the database settings to connect, and only the table says
which options are booleans. So a word now waits until the table has been
read, apart from ZM_DB_* settings, whose words database.php reads itself.
Perl reads the type with each row.

Tested on 1.38's zm138 database with a conf.d file setting
ZM_OPT_FAST_DELETE=yes (0 in the table), ZM_STRICT_VIDEO_CONFIG=off (1)
and ZM_WEB_TITLE=Yes. The installed PHP and Perl gave 'yes', 'off' and
'Yes'; these give '1', '0' and 'Yes'. tests/php/test_config_file_booleans.php
checks the rule.

refs #5289

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 22:37:07 -04:00
Isaac ConnorandClaude Opus 5.5 4d7609d36e fix: let options in zm.conf and conf.d win over the database in the daemons
zm.conf and conf.d are set by the owner of the box; the Config table by the
ZoneMinder admin through the Options page. The owner has to be able to limit
the admin, so a file setting must win. PHP and Perl already let it.
process_configfile() kept only a fixed list of names (database credentials,
paths, server identity, stream socket) and dropped the rest, so zmc, zms and
zmu read every other option from the database alone.

So with ZM_OPT_USE_AUTH=1 in conf.d and 0 in Options, the web UI asked for a
login while nph-zms served streams and snapshots to anyone. The same split
applied to every option, ZM_AUTH_RELAY and ZM_AUTH_HASH_IPS among them.

process_configfile() now records every name = value in
StaticConfig::file_options, later files winning, and zmLoadStaticConfig()
clears it first so a reload forgets a removed line. Config::Load() applies
those values over the database ones, also when the database can't be read.
A boolean may be written yes/no, true/false or on/off as well as 1/0
(ConfigFileValue), since the Config table's 1/0 convention is not what
people type into a file. Overrides are logged by name only, as the value may
be a secret.

Tested live on 1.38: with ZM_OPT_USE_AUTH=1 in conf.d and 0 in the database,
an unauthenticated nph-zms snapshot request answered 200 with an image
before and 403 after. Without the override it still answers 200.

refs #5289

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 22:27:19 -04:00
Isaac ConnorandClaude Opus 5.5 68298351ab feat: report which streaming services each monitor uses in telemetry
Add JanusEnabled, Go2RTCEnabled, RTSP2WebEnabled and RTSPServer to the
per-monitor telemetry, so we can tell whether Janus and RTSP2Web are still
in use before deciding whether to deprecate them. Nothing in the existing
payload says.

Bring the privacy statement's list of collected monitor fields up to date
too. It listed Function, which no longer exists, and left out Capturing,
Analysing and Recording, and the source path, which is sent with its user
name, password and host replaced. Only en_gb is updated; the other
translations keep their own lists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 20:27:13 -04:00
Nic Boet df47b3b98c fix: make startpackpack.sh checkvars detect an empty variable
checkvars looped over the values of the five variables, unquoted, so an
empty one dropped out of the list and was never checked: the build went
on with a malformed VERSION/RELEASE instead of stopping with exit 98.

Loop over the variable names and test each value with indirect
expansion. A test that empties each variable in turn shows checkvars
now stops for every one of them; with all five set it continues as
before.
2026-10-15 18:55:30 -05:00
Nic Boet cb176ceffc ci: pass the release tag to run steps through env
release-source-tarball pasted ${{ inputs.tag }},
${{ github.event.release.tag_name }} and the step outputs derived from
them straight into the run: scripts. GitHub substitutes expressions
into the script text before bash parses it, so a tag containing shell
syntax ran as code in a job with contents: write. Only people who can
publish a release or dispatch the workflow can set the tag, so this is
hardening, not an exposure.

Pass each value through env: and read it as a shell variable, as
GitHub's security hardening guide recommends. Normal tags produce the
same outputs and tarball name as before; the `with:` inputs are not
shell and are unchanged.
2026-10-15 18:55:30 -05:00
Isaac ConnorandClaude Opus 5.5 cdb74426bb fix: index an event MP4 whose last fragment lasts 0 ticks
An event that closes on a keyframe ends in a fragment holding that frame
alone. The muxer gives the file's last sample the packet's duration, which
camera packets leave at 0, so the last sidx reference would last 0 ticks
and build_sidx_region refused the whole index ("Could not index ...; it
will play, but a player must read it all before the first frame").

Fold a zero-length last reference into the one before it. That reference
still points at a real moof, so seeking is unchanged. A lone zero-length
fragment, or one mid-file, is still refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 18:33:10 -04:00
IgorA100 c398c6356e Avoiding errors when stopping a Janus stream (MonitorStream.js) 2026-10-15 23:22:24 +03:00
Isaac Connor 5871d50383 Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-10-15 09:00:59 -04:00
Isaac ConnorandClaude Opus 5.5 514254b967 fix: report a linked monitor's alarm only from its alarm state
MonitorLink::score() reported an alarm whenever the linked monitor's
last_event_id changed (4356a6dea), to catch an alarm that went from ALARM
through ALERT to IDLE between two checks. A new event is not an alarm,
though. A monitor recording continuously starts a new event at every section
boundary, so each one gave its linked monitors a "Linked" alarm, and an
on-demand one a camera reconnect, with no motion anywhere. A monitor with
Recording=None never opens events, so for it the latch did nothing.

Report alarm status only: the frame score in ALARM, and 1 in ALERT so a linked
event stays open through the source's post-event frames (8fc1992e4). The state
stays in shared memory until the source analyses its next frame, and the
receiving monitor checks the link on every packet (every 100 ms while an
on-demand one is paused), so an alarm is still seen.

tests/zm_monitorlink_score.cpp points a MonitorLink at a local SharedData and
checks IDLE, ALARM and ALERT, and that a new event while idle scores 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 08:51:35 -04:00
Isaac ConnorandClaude Opus 5.5 34084a229d fix: wake an on-demand monitor when a linked monitor alarms
A monitor with Capturing=Ondemand and LinkedMonitors never recorded a linked
alarm unless someone happened to be watching it. Links are evaluated in
Analyse(), per captured packet, and zmc pauses an on-demand camera, stopping
its analysis thread, 10 s after the last viewer. While paused nothing looked
at the links, so every alarm on the linked monitor was missed. This is the
low-bandwidth setup of a substream that analyses and a main stream that
records on demand.

zmc's on-demand decision moves into Monitor::CheckOndemand(), around a
DecideOndemand() table that can be tested:

- While paused, the links are checked on every pass. The analysis thread is
  stopped then, so the capture thread reads them without racing it. An alarm
  reopens the camera.
- An unwatched monitor keeps capturing while it is alarmed or in its
  post-event frames, instead of pausing in the middle of the event.
- A link only reports an alarm while it lasts, and reopening the camera can
  take longer than that (2.5 s against a local camera). So the wake is
  remembered for up to 30 s, and the first packet Analyse() scores counts it
  as a linked alarm, then clears it.

Tested live on 1.38 with a paused on-demand passthrough monitor linked to an
analysing one. Before: an 8 s forced alarm on the source recorded nothing.
After: the monitor woke within 0.1 s, alarmed 2.5 s later and recorded the
event. A 1 s alarm, over before the camera reopened, was also recorded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 08:33:11 -04:00
Isaac ConnorandClaude Opus 5.5 0960b2064b fix: log the database error when dbQuery's prepare or query returns false
dbQuery()'s two error paths for a prepare() or query() that returns false
logged $pdo->errorInfo. $pdo is not defined there, so PHP warned twice and
the message ended without the error. They also read dbLastError() from the
connection only after ZM\Error() had logged; with a database log target that
inserts into Logs through the same connection, which replaces its errorInfo,
so dbLastError() came back as "00000" instead of the error.

Read the error once, before logging, and use it for both. The query() path
also said "Error preparing" for a statement it ran directly.

These paths run when PDO's error mode doesn't throw; dbConnect() sets
ERRMODE_EXCEPTION, so normally the catch below handles the failure.

tests/php/test_database_error_paths.php drives both paths with
ERRMODE_SILENT and checks for no PHP warning and the real error text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 07:58:26 -04:00
Isaac Connor 25e33360d3 Merge pull request #5286 from nabbi/perf/emulated-prepares
perf: one database round trip per query for ZoneMinder's PHP on 8.1+
2026-10-15 07:56:20 -04:00
Nic Boet 35a8daf99e perf: emulate prepares for ZoneMinder's own queries on PHP 8.1+
dbConnect() turns emulated prepares off, so every query of the web UI, the
ajax calls and the includes the API runs (config, servers, users,
permissions) is a server-side prepare: prepare, execute and close, three
round trips to the database where one would do. From PHP 8.1, pdo_mysql
returns integers and floats as PHP ints and floats with emulated prepares
too, so values keep the types they have now. Emulate prepares there and keep
server-side prepares on older PHP, where every value would become a string.

Emulated prepares quote parameters bound as strings, which breaks LIMIT ?.
dbQuery() now binds integer values as integers (everything else as strings,
as execute() did), and the log and watch ajax calls cast their validated
offset and limit to int. With emulation, PDO would also run several
statements given in one string; MYSQL_ATTR_MULTI_STATEMENTS is turned off so
that is refused as before. CakePHP's own connection is not changed: it
already uses PDO's default, emulated prepares.

tests/php/test_database_emulated_prepares.php compares every column of every
table read through both kinds of prepare (types and values), checks
aggregates, LIMIT with positional and named integers, string and null
parameters, and that two statements in one string are refused.
2026-10-14 22:41:42 -05:00
Isaac ConnorandClaude Opus 5.5 1fc6630d75 refactor: drop the linked-monitor re-parse from Monitor::Reload() refs #5275
#5276 re-parsed LinkedMonitors in Reload() because nothing else did until
the next reconnect. Since #5239, every reload is a reconnect: zmc Close()s
and disconnect()s the monitor, calls Reload(), then connect(), and
connect() already calls ReloadLinkedMonitors(). The call in Reload()
queried the database once per linked monitor for an expression connect()
then threw away.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 20:45:39 -04:00
Isaac ConnorandClaude Opus 5.5 1ca880359e fix: start a planar crop on the chroma grid refs #5265
A YUV420P chroma sample covers 2x2 luma pixels. Image::Crop started the
chroma planes at lo_x >> 1 and lo_y >> 1, so a crop starting on an odd
column or row had its chroma half a pixel off its luma. nph-zms zoom picks
any position, so a zoomed live view could show colour fringes.

For planar formats, move the crop window back to the chroma grid before
copying, keeping its size. Moving left or up can't leave the image.

Also use the existing ceil_rshift() for the chroma copy sizes instead of
writing the same calculation inline, moving it above Crop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 20:16:05 -04:00
Isaac Connor a5b1ce3bee Merge pull request #5266 from nabbi/fix/b79-image-crop-planar
fix-high: crop into a buffer laid out the way Image::AssignDirect expects
2026-10-14 20:15:46 -04:00
Isaac ConnorandClaude Opus 5.5 2d353fe43c fix: run the shared-memory reload action through zmc's SIGHUP reload fixes #5239
Monitor::CheckAction() handled the RELOAD action (zmu --reload, or a script
setting it through ZoneMinder::Memory) by calling Reload() in place. That
runs on zmc's capture thread, and Monitor::Load() rewrites settings such as
label_format, orientation and the image sizes while the decoder and analysis
threads read them unlocked.

SIGHUP already reloads safely: zmc leaves its capture loop, Close()s and
disconnect()s each monitor, which stops those threads, then Reload()s and
reconnects. Have the action set zm_reload, as the SIGHUP handler does, so
both take that path.

zmc reloads every monitor it runs this way, not only the one the action was
sent to; zmc normally runs one.

Tested live on 1.38 with zmu --reload against a running zmc: the event closes,
the same process reloads and reconnects, capture resumes and a new event
opens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 19:07:40 -04:00
Isaac Connor bdd5ec93c2 Merge pull request #5284 from nabbi/fix/b102-zms-403-status
fix-medium: answer zms refusals with 403 behind nginx + fcgiwrap too
2026-10-14 18:59:25 -04:00
Isaac Connor edad61f536 Merge pull request #5278 from nabbi/fix/b85-stream-crop-zoom-snapshot
fix-low: scale last_crop back with the zoom the crop was computed for
2026-10-14 18:57:36 -04:00
Isaac Connor c0251b3ac5 Merge pull request #5276 from nabbi/fix/b84-reload-linked-monitors
fix-medium: re-parse LinkedMonitors on a monitor reload
2026-10-14 18:52:23 -04:00
Isaac ConnorandClaude Opus 5.5 31eeb486ca fix: reject LinkedMonitors ids that don't fit an unsigned int refs #5273
std::stoul returns an unsigned long, and Token assigned it to an unsigned
int monitor or zone id. On 64-bit, 99999999999 parsed and was truncated
to 1215752191, so a LinkedMonitors value could quietly link a different
monitor than the one typed. It only failed because that id didn't exist.

Move the parsing into Token::parse_monitor_link(), which rejects an id
above UINT_MAX like any other value that isn't a number, so the token is
ignored with the same warning. The function is static so the test can
check the parsed ids without a database.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 18:40:37 -04:00
Isaac Connor c5d0ac2fb2 Merge pull request #5274 from nabbi/fix/b83-monitorlink-bad-token
fix-high: ignore LinkedMonitors tokens zmc can't link instead of crashing
2026-10-14 18:36:18 -04:00
Isaac Connor af039e8091 Merge pull request #5272 from nabbi/fix/b81-monitorlink-own-expression
fix-medium: keep the linked-monitor expression's own copy of its string
2026-10-14 18:31:14 -04:00
Isaac Connor 503a1c0c74 Merge pull request #5270 from nabbi/fix/b82-poll-thread-stop
fix-medium: let PollThread::Stop end the wait between polls
2026-10-14 18:25:18 -04:00
Isaac Connor 4aca8852cd Merge pull request #5268 from nabbi/fix/b80-zms-step-wrapped
fix-low: stay on the newest frame when stepping forward in wrapped buffered playback
2026-10-14 17:54:38 -04:00
Nic BoetandClaude Opus 5.5 d27b9612f0 fix: answer zms refusals with 403 behind nginx + fcgiwrap too
A refused nph-zms request (no or bad credentials, or a monitor or event
the user may not view) wrote only the raw NPH status line,
HTTP/1.0 403 Forbidden. Apache passes it through, but behind nginx and
fcgiwrap it is not taken as the status: the client got 200 with an empty
body, so an app could not tell a refusal (say, an expired token) from an
answer. Under the plain zms name Apache answered 500 for the same line.

Write a Status: 403 header as well in NPH mode, and only that header
otherwise, so every server answers 403.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:05:36 -05:00
Isaac Connor 9b07f8cd1f Merge pull request #5282 from ZoneMinder/dependabot/github_actions/github/codeql-action/init-4.38.3
chore(deps): Bump github/codeql-action/init from 4.38.2 to 4.38.3
2026-10-13 20:13:28 -04:00
Isaac Connor 0ebad62f5b Merge pull request #5281 from ZoneMinder/dependabot/github_actions/easingthemes/ssh-deploy-6.0.3
chore(deps): Bump easingthemes/ssh-deploy from 6.0.1 to 6.0.3
2026-10-13 20:13:19 -04:00
Isaac Connor ed3f1a5a49 Merge pull request #5280 from ZoneMinder/dependabot/github_actions/github/codeql-action/analyze-4.38.3
chore(deps): Bump github/codeql-action/analyze from 4.38.2 to 4.38.3
2026-10-13 20:12:51 -04:00
Isaac Connor 6d081aed69 Merge pull request #5279 from ZoneMinder/dependabot/github_actions/github/codeql-action/autobuild-4.38.3
chore(deps): Bump github/codeql-action/autobuild from 4.38.2 to 4.38.3
2026-10-13 20:12:31 -04:00
dependabot[bot] b5077b450d chore(deps): Bump github/codeql-action/init from 4.38.2 to 4.38.3
Bumps [github/codeql-action/init](https://github.com/github/codeql-action) from 4.38.2 to 4.38.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2...24c54180a607b1449ed407dd24f251e4e9147c8d)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.38.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-13 22:27:25 +00:00
dependabot[bot] 802d3dd273 chore(deps): Bump easingthemes/ssh-deploy from 6.0.1 to 6.0.3
Bumps [easingthemes/ssh-deploy](https://github.com/easingthemes/ssh-deploy) from 6.0.1 to 6.0.3.
- [Release notes](https://github.com/easingthemes/ssh-deploy/releases)
- [Changelog](https://github.com/easingthemes/ssh-deploy/blob/main/docs/CHANGELOG.md)
- [Commits](https://github.com/easingthemes/ssh-deploy/compare/5d8aeab1a56041e269567e67a08ce00df324a617...2cc5b27bf3029d0455dd5e09fe02633904031447)

---
updated-dependencies:
- dependency-name: easingthemes/ssh-deploy
  dependency-version: 6.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-13 22:26:21 +00:00
dependabot[bot] 58040d2a3e chore(deps): Bump github/codeql-action/analyze from 4.38.2 to 4.38.3
Bumps [github/codeql-action/analyze](https://github.com/github/codeql-action) from 4.38.2 to 4.38.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2...24c54180a607b1449ed407dd24f251e4e9147c8d)

---
updated-dependencies:
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.38.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-13 22:26:14 +00:00
dependabot[bot] 0a6719979b chore(deps): Bump github/codeql-action/autobuild from 4.38.2 to 4.38.3
Bumps [github/codeql-action/autobuild](https://github.com/github/codeql-action) from 4.38.2 to 4.38.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2...24c54180a607b1449ed407dd24f251e4e9147c8d)

---
updated-dependencies:
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.38.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-13 22:25:06 +00:00
Isaac Connor a7b8d3a075 Merge pull request #5208 from ZoneMinder/db-log-pause-queue-only
fix: keep only the database queue thread out of database logging
2026-10-13 18:18:58 -04:00
Isaac Connor 6e06dc31ab Merge pull request #5203 from nabbi/fix/b52-logger-reload
fix-medium: re-initialise the logger in place on reload instead of deleting it
2026-10-13 18:18:15 -04:00
Isaac Connor 4581360cf7 Merge pull request #5201 from nabbi/fix/b53-close-orphaned-events
fix-high: close events left open by a capture daemon that died
2026-10-13 18:17:38 -04:00
Isaac Connor bf447c96a2 Merge pull request #5247 from nabbi/fix/b11-reolink-uniview-json
fix-medium: load JSON through JSON::MaybeXS in Reolink_HTTP and Uniview, add a Reolink_HTTP Controls row
2026-10-13 18:16:40 -04:00
Isaac Connor 24c1c6ab98 Merge pull request #5243 from nabbi/fix/b16-user-self-edit-api
fix-medium: honour ZM_USER_SELF_EDIT in the users API
2026-10-13 18:15:54 -04:00
Isaac Connor 969069eacf Merge pull request #5241 from nabbi/fix/b68-signal-colour-luma
fix-medium: match SignalCheckColour by its luma on 1-byte-per-pixel captures
2026-10-13 18:14:42 -04:00
Isaac Connor 7e02d9a5d4 Merge pull request #5214 from nabbi/fix/b76-zone-pixel-clamp
fix-high: clamp pixel zone coordinates to the monitor before rasterising
2026-10-13 18:14:03 -04:00
Isaac Connor e5ee92ed5e Merge pull request #5249 from nabbi/fix/b61-packet-trylock
fix-low: don't let a failed ZMPacket::trylock overwrite the lock flag
2026-10-13 18:11:50 -04:00
Isaac Connor 000692daa4 Merge pull request #5245 from nabbi/fix/b19-intelgpu-inline-script
fix-low: drop the Intel GPU view's inline script that CSP blocks
2026-10-13 18:10:31 -04:00