Commit Graph

3050 Commits

Author SHA1 Message Date
Isaac Connor
e1bd60116a fix: add credential fallback chain in ONVIF control module
When ControlAddress does not contain authentication info, fall back
to Monitor->ONVIF_Username/ONVIF_Password, then Monitor->User/Pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 12:32:28 -05:00
Isaac Connor
3432e39c45 feat: add Remember Me checkbox to login page
Add ZM_OPT_USE_REMEMBER_ME config option (auth section, requires
ZM_OPT_USE_AUTH) that controls whether a Remember Me checkbox appears
on the login form. When enabled and unchecked, the session cookie
lifetime is set to 0 so the browser discards it on close, logging the
user out. When checked, the session persists for ZM_COOKIE_LIFETIME.
When the option is disabled, behavior is unchanged.

- ConfigData.pm.in: new ZM_OPT_USE_REMEMBER_ME boolean option
- login.php: checkbox between password field and reCAPTCHA/submit
- session.php: use lifetime=0 when remember me is off
- actions/login.php: set/clear ZM_REMEMBER_ME cookie on login, also
  update $_COOKIE so zm_session_start sees it in the same request
- auth.php: clear ZM_REMEMBER_ME cookie on logout
- en_gb.php: add RememberMe translation string

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:41:25 -05:00
Isaac Connor
3de87e224a Merge pull request #4617 from nabbi/remove-makemaker-perl-install
build: replace Perl ExtUtils::MakeMaker with native CMake install
2026-03-04 20:34:46 -05:00
Isaac Connor
48a556fac6 Merge branch 'master' into feature/custom-model-training 2026-03-04 16:45:54 -05:00
Isaac Connor
e72423c7f0 fix: add SSL certificate verification fallback to base Control class
When cameras use HTTPS with self-signed or invalid certificates, LWP's
default SSL verification causes connection failures. Add automatic
fallback to all three HTTP methods (get, put, post) in the base Control
class: if a request fails with an SSL/certificate error, disable
verification and retry. Once disabled, the relaxed setting persists for
the rest of the control session via the ssl_verify_disabled flag.

This follows the pattern already used in Dahua.pm and
TapoC520WS_ONVIF.pm but applies it universally so all control modules
benefit without needing individual SSL handling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 12:44:19 -05:00
Pliable Pixels
1189011060 fix: use content directory for training data fallback path
Change default training data directory from @ZM_CACHEDIR@/training to
@ZM_CONTENTDIR@/training so it lives alongside events storage instead
of inside the web cache folder. Update PHP fallback to use
dirname(ZM_DIR_EVENTS) accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 12:24:44 -05:00
Pliable Pixels
62678b24f8 fix: address Copilot review — path traversal, temp leak, double undo, help text
- Fix path traversal via directory prefix matching: append
  DIRECTORY_SEPARATOR to base path before strpos containment check
  (2 locations in training.php)
- Fix temp file leak: rename tempnam() base file to .jpg instead of
  creating a second file, leaving the original orphaned
- Remove raw_output from detect response (information disclosure)
- Fix double _pushUndo on Delete key (keydown handler + deleteAnnotation)
- Fix help text: "alongside events storage" → "inside the ZoneMinder
  cache directory" to match actual ZM_DIR_CACHE default (2 locations)
- Add missing .frame-total span element in event.php

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:25:07 -05:00
Pliable Pixels
772587b353 fix: improve TRAINING_DATA_DIR help text for empty path behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:35:53 -05:00
Pliable Pixels
a2ff391eb1 feat: add Detect button to run object detection on current frame
Add ZM_TRAINING_DETECT_SCRIPT config option for specifying the path
to an external detection script (e.g. zm_detect.py). When configured,
a Detect button appears in the annotation editor that:
- Runs the script with -f <image> -m <monitor_id>
- Parses the --SPLIT-- JSON output for labels, boxes, confidences
- Displays results as orange (pending) bounding boxes
- Users can accept (checkmark) or reject (x) each detection
- Only accepted annotations are saved to the training set

Also adds accept/reject UI in the sidebar object list, with orange
color for pending detections and normal colors for accepted ones.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:55:00 -05:00
Pliable Pixels
a8c9c180b6 feat: add custom model training annotation UI
Add canvas-based bounding box annotation editor to the event view for
correcting object detection results and building YOLO training datasets.

- Two new config options: ZM_OPT_TRAINING (toggle) and ZM_TRAINING_DATA_DIR
- AJAX backend (training.php) with load/save/delete/status actions
- Canvas annotation editor (training.js) with draw/resize/relabel/undo
- Frame navigation (alarm/snapshot/objdetect/numbered frames)
- Roboflow-compatible YOLO output (images/all/, labels/all/, data.yaml)
- Training data statistics with per-class image counts and guidance
- Full i18n support via en_gb.php SLANG/OLANG entries
- Label validation, YOLO coordinate clamping, audit logging
- DB migration for existing installs (zm_update-1.39.2.sql)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:35:55 -05:00
Isaac Connor
796329a98d fix: zmDbDo error logging now substitutes all SQL placeholders with values
The error path was missing the /g flag on the regex replacing ? with %s,
so only the first placeholder was replaced. It also dumped bind values as
a space-separated string instead of using sprintf to substitute them into
the query. Now matches the existing debug path pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 23:05:12 -05:00
Isaac Connor
e6ace6fcf4 feat: add AUDIT logging level for tracking administrative changes
Add a new AUDIT logging level (-5) between PANIC (-4) and NOLOG (shifted
to -6) across C++, PHP, and Perl loggers. AUDIT entries use code 'AUD'
and syslog priority LOG_NOTICE. They record who changed what, from where,
for monitors, filters, users, config, roles, groups, zones, states,
servers, storage, events, snapshots, control caps, and login/logout.

AUDIT entries have their own retention period (ZM_LOG_AUDIT_DATABASE_LIMIT,
default 1 year) separate from regular log pruning. The log pruning in
zmstats.pl and zmaudit.pl now excludes AUDIT rows from regular pruning
and prunes them independently.

Critical safety: the C++ termination logic is changed from
'if (level <= FATAL)' to 'if (level == FATAL || level == PANIC)' to
prevent AUDIT-level log calls from killing the process.

Includes db migration zm_update-1.39.1.sql to shift any stored NOLOG
config values from -5 to -6.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:19:20 -05:00
Isaac Connor
a2bf848ce0 feat: expand ONVIF config_types with full device/media/imaging/PTZ queries
Add config type entries for Hostname, DNS, NTP, NetworkInterfaces,
Capabilities, Scopes, Services, VideoSources, VideoSourceConfigurations,
AudioSources, AudioSourceConfigurations, AudioEncoderConfigurations,
StreamUri, SnapshotUri, ImagingOptions, PTZConfigurations, PTZNodes,
PTZPresets, and PTZStatus.

- Support __PROFILE_TOKEN__ substitution in request bodies
- Add writable flag to config types and enforce it in set_config
- Add NTP set handler for SetNTP ONVIF command
- Organize config_types by ONVIF service (device, media, imaging, PTZ)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:16:55 -05:00
Isaac Connor
a5fd6e063e feat: add --protocol mode to zmcontrol.pl for direct module testing
Add --protocol, --address, and --device CLI options that bypass the
database and socket machinery to load a control module directly and
execute a single command. This enables standalone testing of control
modules (e.g. ONVIF.pm get_config) without a running ZoneMinder
instance. Also update POD with full documentation and examples.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:07:49 -05:00
Nic Boet
600f5a12e8 build: add selective man3 generation for audited Perl modules
Generate man3 pages only for the 7 ZoneMinder Perl modules whose POD
documentation was audited and confirmed accurate:

  Verified accurate API docs:
  - ZoneMinder::Memory (shared memory API, 18 methods)
  - ZoneMinder::Logger (logging API, all levels/methods/options)
  - ZoneMinder::Control::Dahua (full PTZ method reference)

  Useful prose documentation:
  - ZoneMinder::Control::Reolink_HTTP (auth flow, config, features)
  - ZoneMinder::Control::Amcrest_HTTP (security warning, timing docs)
  - ZoneMinder::Control::Trendnet (setup guide, capability settings)
  - ZoneMinder::Control::Instar720p (CGI parameter reference)

The remaining ~3,100 modules (66 boilerplate skeletons, 3,005 WSDL
stubs, 14 with no POD) are excluded.

Build-time filenames use "/" separators to avoid GNU make's "::"
double-colon rule syntax conflict. Installed filenames use the
standard Perl "::" convention (e.g., ZoneMinder::Memory.3pm.gz).

Gated behind BUILD_MAN (default ON, same as section 8 script pages).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 14:47:42 -06:00
Nic Boet
c23869b6ac build: replace Perl ExtUtils::MakeMaker with pure CMake install
MakeMaker was only used to copy .pm files — no XS compilation, no binary
linking, no dependency resolution. Its hardcoded "Makefile" output name
conflicts with cmake's generated Makefile for in-source builds, and using
FIRST_MAKEFILE=MakefilePerl causes thousands of "uninitialized value"
warnings because MM.pm stats the wrong file.

Replace with native CMake install(DIRECTORY ... FILES_MATCHING PATTERN
"*.pm") directives. Perl module install path is auto-detected at configure
time via `perl -MConfig` (vendorlib on Linux, sitelib on FreeBSD),
overridable with -DZM_PERL_INSTALL_PATH=<path>.

What's removed:
- ExtUtils::MakeMaker as build dependency
- Three perl+make subprocesses at build time (zmperlmodules,
  zmonvifmodules, zmonvifproxy build targets)
- ~6000 auto-generated man3 pages from WSDL stubs
- MakeMaker scaffolding: Makefile.PL, MANIFEST, META.yml, Changes,
  README, and t/ZoneMinder.t test stub

What's preserved:
- configure_file() for .pm.in templates (same behavior)
- ZM_PERL_SEARCH_PATH (independent mechanism, unchanged)
- Section 8 man pages for .pl scripts (Pod2Man.cmake, unaffected)
- DESTDIR support (CMake install() handles natively)
- Installed file paths (perl -MConfig returns same paths MakeMaker used)

Verified: 3102 .pm files installed, 0 .pm.in files, 0 .3pm man pages,
no @VERSION@ markers in generated files, DESTDIR and user override work.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 14:47:35 -06:00
Isaac Connor
409a9391b7 feat: add get_config/set_config to ONVIF control module
Add configuration read/write support following the Uniview.pm pattern.
get_config() queries five ONVIF categories (DeviceInformation, DateTime,
ImagingSettings, VideoEncoderConfiguration, Profiles) via SOAP and returns
parsed XML as hashes. set_config() supports writing ImagingSettings
(Brightness/Contrast/Saturation/Sharpness/ColorSaturation) and DateTime,
treating other categories as read-only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 12:10:10 -05:00
Isaac Connor
a329b34486 fix: repair imaging bugs in onvif, Reolink, Netcat, and TapoC520WS control modules
- onvif.pm: irisAbsClose checked lowercase 'brightness' so getCamParams
  was never called on decrease, sending stale/zero values
- Reolink.pm: same brightness case bug, plus whiteAbsIn and whiteAbsOut
  built the SOAP message but never called sendCmd — contrast changes
  were silently discarded
- Netcat.pm: same brightness case bug, plus debug() call should be Debug()
- TapoC520WS_ONVIF.pm: same brightness case bug

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 11:48:45 -05:00
Isaac Connor
57054cdd5b feat: add unified ONVIF.pm control module replacing four per-vendor copies
Single ONVIF SOAP/PTZ implementation that replaces onvif.pm, Reolink.pm,
Netcat.pm, and TapoC520WS_ONVIF.pm. All state is kept in instance variables
(no package globals), SSL verification falls back automatically, and
sendCmd routes to the correct ONVIF service endpoint per command type.

Bug fixes from the originals:
- Brightness decrease checked lowercase 'brightness' (never matched)
- whiteAbsIn/whiteAbsOut in Reolink/Netcat/TapoC520WS never called sendCmd
- Imaging commands sent to PTZ endpoint instead of /onvif/imaging
- Reboot sent to PTZ endpoint instead of /onvif/device_service
- Package globals leaked state between camera instances

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 11:46:34 -05:00
Isaac Connor
d74913e3bf fix: resolve multiple bugs in AxisV2 control module and add config/probe support
Fix critical crash in open() where guess_credentials() boolean return was
treated as URI object. Rewrite open() to use base class get_realm() for
auth discovery, matching the Uniview/HikVision pattern.

Bug fixes:
- focusRelNear: remove double-$self in recursive call, use instance var
- focusRelFar: fix copy-paste error calling focusRelNear instead of self,
  remove double-$self, use instance var
- focusAbs: fix .cgi.cgi typo in opticssetup URL
- Replace package-global $use_optics with $$self{use_optics} to prevent
  state leaking between camera instances
- Remove unused our $uri, use ZoneMinder::Config, use URI imports
- Move use LWP::UserAgent to module-level imports

New features:
- get_config/set_config via Axis param.cgi API
- probe() for network camera discovery
- rtsp_url() returning standard Axis RTSP path

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 10:10:49 -05:00
Isaac Connor
37e377acf4 feat: implement LAPI config get/set and fix PTZ in Uniview control module
Replace empty get_config/set_config stubs with working implementations
using Uniview's native LAPI JSON REST API. Modernize open() to use base
class guess_credentials() and get_realm() instead of duplicated auth
logic. Rename put() to PutCmd() to fix broken PTZ methods. Remove
package-level globals in favor of instance variables. Add lapi_get/
lapi_put helpers, probe via LAPI with ISAPI fallback, and rtsp_url().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 09:58:00 -05:00
Isaac Connor
ca22ae3737 Remove fatal version check. Just error. 2026-02-12 16:53:29 -05:00
Isaac Connor
c250eadcea fix: use ${PERL_EXECUTABLE} instead of hardcoded perl in CMake builds
Replace 4 hardcoded `perl` invocations with `${PERL_EXECUTABLE}` from
find_package(Perl) so builds work when perl isn't in PATH or the wrong
perl would be found (NixOS, custom installs, Homebrew vs system).

Also: fix ZMCONFGEN_RESULT variable case mismatch in error message,
remove deprecated IMMEDIATE keyword from configure_file(), bump
cmake_minimum_required from 3.5 to 3.12 (C++17 requires 3.9+), and
remove dead C++11 fallback for CMake < 3.8 in ConfigureBaseTargets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 12:25:37 -05:00
Isaac Connor
fcfc7db0c7 Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-02-09 09:29:41 -05:00
Isaac Connor
f7858f3770 feat: add events command to zmonvif-probe.pl
Add 'events' command to check if an ONVIF camera supports the events
service. Returns "Events: yes" or "Events: no" for easy parsing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 09:29:36 -05:00
Nic Boet
d66a3525bd feat: detect MariaDB-native command names with fallback to MySQL legacy names
MariaDB is deprecating mysql-prefixed utility names (mysqldump,
mysql) in favour of its own (mariadb-dump, mariadb). Add
findDbCommand() to ZoneMinder::General that probes for the
MariaDB-native binary first and falls back to the legacy name.
Results are cached per-process. Update the three call sites in
zmupdate.pl.in and zmcamtool.pl.in.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 13:19:32 -06:00
Isaac Connor
4ebbc540ca Merge pull request #4601 from pliablepixels/fix-tag-filtering
fix: correct tag filter operator handling for No Tag and Any Tag
2026-02-07 15:38:11 -05:00
Pliable Pixels
79253dc374 fix: address review feedback for tag filter handling
- Add IS NOT operator check alongside != in PHP FilterTerm.php
  (was already handled in Perl but missing from PHP)
- Add defined() guard on $term->{val} in Perl Filter.pm to avoid
  uninitialized value warnings with malformed/legacy saved filters

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 13:11:13 -05:00
Pliable Pixels
1188635e9a fix: correct tag filter operator handling for "No Tag" and "Any Tag"
The filter system ignored the operator (= vs !=) when generating SQL
for the special tag values "No Tag" (0) and "Any Tag" (-1).

In PHP (FilterTerm.php), "Tag != Any Tag" produced EXISTS instead of
NOT EXISTS, returning events WITH tags instead of events WITHOUT tags.

In Perl (Filter.pm), != was not handled as a special case and fell
through to generic SQL (T.Id != -1), which excluded events with no
tags because LEFT JOIN produces NULL and NULL != -1 evaluates to
UNKNOWN in SQL. Additionally, T.Id was unconditionally prepended for
all tag values, producing invalid SQL (T.IdEXISTS) for the special
cases that use EXISTS/NOT EXISTS subqueries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 13:01:39 -05:00
Isaac Connor
eb7ad81e40 fix: correct syntax error and missing parameter in Database.pm
- zmDbDo: fix mismatched parentheses in Error() call
- zmDbGetMonitorAndControl: pass $id parameter to zmDbFetchOne

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 13:44:49 -05:00
copilot-swe-agent[bot]
27793980ef fix: Address code review feedback
- Add SSL verification state tracking to Dahua.pm to ensure retry logic works for all requests
- Add SSL retry logic to Dahua.pm sendCmd method
- Remove redundant 'use IO::Socket::SSL' statements from TapoC520WS_ONVIF.pm retry blocks

refs #TBD

Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
2026-02-02 14:37:57 +00:00
copilot-swe-agent[bot]
bce080c735 feat: Enable SSL certificate verification with fallback for all components
Enable TLS peer certificate verification by default in all components that communicate over HTTPS. If SSL verification fails, log a warning and retry without verification to maintain backward compatibility with cameras using self-signed certificates.

Changes:
- C++ (zm_monitor_go2rtc.cpp): Enable SSL verification for all curl operations (3 locations)
- C++ (zm_monitor_rtsp2web.cpp): Enable SSL verification for all curl operations (3 locations)
- PHP (monitor_probe.php): Enable SSL verification with fallback logic
- Perl (Dahua.pm): Enable SSL verification with LWP::UserAgent
- Perl (TapoC520WS_ONVIF.pm): Enable SSL verification with retry logic in request methods

refs #TBD

Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
2026-02-02 14:34:19 +00:00
Isaac Connor
a925de0ac1 Add Deleted=false for Monitors count 2026-02-01 14:42:38 -05:00
Isaac Connor
397d2a357e Merge branch 'master' of github.com:ZoneMinder/zoneminder 2026-02-01 10:17:16 -05:00
Isaac Connor
05db51a3ff Fix package name being Frame instead of User 2026-02-01 09:06:14 -05:00
Pliable Pixels
ee99bca21c fix: correct package name in User.pm (ZoneMinder::Frame → ZoneMinder::User)
User.pm declares `package ZoneMinder::Frame` instead of
`package ZoneMinder::User`, clobbering the Frame package namespace
and making the User ORM class unusable via `ZoneMinder::User->find_one()`.

Fixes ZoneMinder/zoneminder#4581

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 09:04:40 -05:00
Isaac Connor
d89f2e59db refactor: rename Janus_Use_RTSP_Restream to Restream
Rename Janus-specific restream fields to be more generic since they are
now used by Go2RTC and RTSP2Web as well:
- Janus_Use_RTSP_Restream → Restream
- Janus_RTSP_User → RTSP_User

Update visibility logic so the Restream checkbox appears when RTSPServer
is enabled AND any streaming service (Janus, Go2RTC, or RTSP2Web) is
selected, rather than only when Janus is enabled.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 18:47:37 -05:00
Isaac Connor
8f5f5bc1c3 DO select, then delete by primary key when cleaning up summary tables. Prevents deadlocks in mysql 2026-01-31 16:54:30 -05:00
Isaac Connor
872cdb1b44 Add Group.pm which is not actually used anywhere 2026-01-31 16:22:24 -05:00
Isaac Connor
bc65f57473 return early if daemon is invalid 2026-01-26 17:22:14 -05:00
Isaac Connor
45695211c3 main:: specificaiton for daemon_patt is wrong 2026-01-26 16:44:34 -05:00
Isaac Connor
5ebf40568c Fix duplicate restart race condition in zmdc.pl
- Always update term_sent_at when sending stop signal, not just when
  unset. This ensures the KILL_DELAY countdown resets properly when
  multiple stop/restart commands are issued.

- Add duplicate restart detection: if a process is already terminating
  with keepalive=true (restart scheduled), ignore subsequent restart
  requests. This prevents race conditions with zmwatch.pl which may
  detect stale heartbeat/shared memory during the restart window and
  send duplicate restart commands.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 14:03:42 -05:00
Isaac Connor
97e5c65fa9 Fix multiple bugs in zmdc.pl daemon control script
- Fix undefined $saddr variable in ZMServer package by using
  sockaddr_un(main::SOCK_FILE) directly
- Fix hash in scalar context that returned bucket ratio instead of
  count, use scalar(keys %terminating_processes)
- Replace die calls with Fatal() for consistent error handling
- Change confusing keepalive=>!undef idiom to keepalive=>1
- Remove unused $win and $ein variables
- Fix typo in comment: processess -> processes
- Add explicit $main:: package qualifier for daemon_patt variable
- Add 30-second timeout when reading server response to prevent
  client from hanging indefinitely

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 12:44:05 -05:00
Isaac Connor
479d3a9b05 Split parsing Path and Control address into their own functions, adding back a hack to handle unescaped passwords on ControlAddress. In Amcrest_HTTP if using ControlAddress fails, fall back to using Path 2026-01-22 11:54:58 -05:00
Isaac Connor
b6ee583454 Merge updates from another branch, cleaning up and improve address/auth parsing and improving put() 2026-01-22 10:03:01 -05:00
Isaac Connor
f702c6c190 Add last_analysis_view_time to perl shm structure 2026-01-16 15:28:43 -05:00
Isaac Connor
0ee1da73cf Remove primark_key 2026-01-14 09:46:31 -05:00
Isaac Connor
376e6b8899 Only set timezone if it is set in config. 2026-01-14 09:33:50 -05:00
Isaac Connor
32ec9dc801 Add defaults for Type and Scheme to prevent warnings in logs due to undefined values 2026-01-14 09:32:08 -05:00
Isaac Connor
201b2bbd06 Set tz in Date::Manip so that returned unixdate from '-1 hour' is in the current timezone, not UTC 2026-01-14 09:31:55 -05:00