Commit Graph
1056 Commits
Author SHA1 Message Date
Divarion_D 2364aae6ee refactor(streaming): extract delay resume helpers from startStream
The delayed-HLS branch inline-computed two things: the resume segment number
parsed from the existing delay playlist (last-or-previous line's _<n>.ts index),
and the delay sleep seconds (delay_minutes*60 reduced ~10s per already-produced
segment, floored at 0). Pull both into pure resolveDelaySegmentStart() and
resolveDelaySleepTime() helpers with unit tests. The playlist merge and the
short-playlist abort stay inline. No behaviour change.

Verified: phpstan level 5 green, phpunit 391/391, make gates green.
2026-08-07 21:01:59 +03:00
Divarion_D 39090e37ba refactor(streaming): extract hasSkipFFProbe and skipFFProbeOutput from startStream
The ffprobe-skip branch of the source loop hand-rolled two things: a scan of the
stream arguments for skip_ffprobe == 1, and the literal assumed h264/aac mpegts
result used when the scan matched. Give both names via pure helpers and cover
them with unit tests. No behaviour change.

Verified: phpstan level 5 green, phpunit 385/385, make gates green.
2026-08-07 20:54:14 +03:00
Divarion_D ececd4aa8f fix(streaming): read the ffprobe cache under the same key it is written
The 300s ffprobe cache is written, existence-checked and deleted under
md5($rSource), but the content read used md5($rStreamSource)
(= parseStreamURL($rSource)). When parseStreamURL rewrote the source the read
fetched a different, usually missing file, so igbinary_unserialize(false)
failed the validity check and every start re-probed instead of hitting the
cache. Read under md5($rSource) so the key matches the write.

Verified: phpstan level 5 green, phpunit 382/382, make gates green.
2026-08-07 20:51:55 +03:00
Divarion_D 24736873f6 chore(phpstan): correct stale "no Composer/PSR-4" bootstrap comments
phpstan-bootstrap.php and phpstan.dist.neon claimed the project "has no
Composer and no PSR-4 namespaces" and referenced the removed src/autoload.php
— both false since the Composer PSR-4 migration (and self-contradicted by the
neon's own excludePaths note about src/vendor/autoload.php). Comment-only:
they now state the bootstrap defines constants and deliberately wires no
project autoloader (PHPStan discovers symbols via paths + scanDirectories).
No behavior change.
2026-08-07 20:51:02 +03:00
Divarion_D 2466ddfc3e chore(tools): remove orphaned gen-module-hashes.php
The script was never wired up (no `make module-hashes` target, no CI/Makefile
caller). Module hash_id generation now lives in the standalone Module_Template
kit; for existing modules, generate inline with
`php -r 'echo bin2hex(random_bytes(16));'`.

Updated the module-dev docs (en + ru) that referenced the removed script /
non-existent `make module-hashes` target to use the one-liner.
2026-08-07 20:49:36 +03:00
Divarion_D 2d885af262 refactor(streaming): extract aacBitstreamFilter from startStream
The {AAC_FILTER} substitution carried the rule inline: emit -bsf:a
aac_adtstoasc only when a copied AAC audio stream is muxed into a non-FLV
container. Give that rule a name and a test via a pure aacBitstreamFilter()
helper. No behaviour change.

Add unit tests: applied for copied AAC in mpegts/empty container, skipped for
FLV, skipped when the codec is not AAC or the output is not a copy.

Verified: phpstan level 5 green, phpunit 382/382, make gates green.
2026-08-07 20:46:10 +03:00
Divarion_D f99048b79f refactor(streaming): extract resolveStreamCodecMeta from startStream
The codec-metadata derivation persisted for a started live stream (player
compatibility, audio/video codec names, resolution snapped to the nearest
standard height) was an inline block reading ffprobe output. Pull it into a
pure resolveStreamCodecMeta() helper taking the ffprobe array and the
player_allow_hevc flag and returning [compatible, audio, video, resolution].

The only external input, SettingsManager::getAll()['player_allow_hevc'], is now
passed in (getAll() just returns the cached settings array, so hoisting the read
out of the guard is free). Add unit tests: non-array/missing-codecs defaults,
compatible h264/aac, resolution snapping, HEVC gating by the allow flag, and
incompatible-but-reported codecs.

Verified: phpstan level 5 green, phpunit 379/379, make gates green.
2026-08-07 20:43:37 +03:00
Divarion_D 8973f5580f refactor(streaming): extract appendHeaderArgument from startStream
The X-XC_VM-Detect / X-XC_VM-Prebuffer header injection was duplicated three
times in startStream: each block looped the argument list to append the header
to an existing 'headers' entry and added a new one if absent. Collapse the three
copies into a single appendHeaderArgument() helper and drop the shared
$rProcessed flag they threaded through (it leaked state between the blocks).

Behaviour is unchanged: the helper uses a local applied flag, and the three call
sites produce the same argument lists as before. Add unit tests covering
append-to-existing, create-when-absent, append-to-every-headers-entry, and the
empty-list case.

Verified: phpstan level 5 green, phpunit 373/373, make gates green.
2026-08-07 20:32:51 +03:00
Divarion_D a1c1d64139 docs(claude): add Agent skills section pointing to docs/agents
Restores the pointer the engineering skills use to find the per-repo
issue-tracker and domain-doc config (docs/agents/*), lost during a
concurrent history rewrite.
2026-08-07 20:28:41 +03:00
Divarion_D a0ed41df16 docs(agents): add issue-tracker + domain consumer docs
Per-repo config the engineering skills read: docs/agents/issue-tracker.md
(GitHub Issues via gh for Vateron-Media/XC_VM) and docs/agents/domain.md
(single-context CONTEXT.md + docs/adr/ consumer rules).
2026-08-07 20:27:42 +03:00
Divarion_D b88ae60dc1 refactor(streaming): extract startStream probe/failover helpers and default its command variables
Continue breaking down StreamProcess::startStream:
  - extract resolveProbeSettings() (ffprobe/analysis timing) and
    rotateSourcesPastCurrent() (source-failover ordering) as private static
    helpers, with unit tests locking in their behaviour;
  - simplify 15 inverted empty-if/else blocks across the class into a single
    positive condition (no behaviour change).

Also fix the latent undefined-variable bugs the refactor surfaced under PHPStan:
startStream assembles the ffmpeg command from state produced inside the source
failover loop (which closes before the command is built) and inside the
non-custom_ffmpeg branch. On an empty source list, or when a custom ffmpeg line
is used, several variables were read while possibly undefined -- masked at
runtime only by ternary guards and suppressed in the PHPStan baseline. Default
them at the two scopes that own them:
  - loop-scoped, read after the loop: $rSource, $rRealSource, $rStreamSource,
    $rProtocol, $rFFProbeOutput
  - non-custom_ffmpeg-branch-scoped, read in the {MAP}/{GEN_PTS}/{READ_NATIVE}
    substitution and delay sleep: $rMap, $rGenPTS, $rReadNative, $rSleepTime
and drop the 9 now-obsolete entries from phpstan-baseline.neon.

Behaviour is unchanged on the happy path (the loop/branch overwrite the
defaults) and the defaults match the existing runtime ternary-guard results.

Verified: phpstan level 5 green (whole project, entries un-suppressed),
phpunit 369/369, make gates green.
2026-08-07 20:20:09 +03:00
Divarion_D 2abd19b0d5 chore(github): add composer to dependabot, fix stale AI instructions
dependabot.yml: the comment claimed "no Composer/npm manifests committed",
but src/composer.json + composer.lock ARE committed. Added a grouped
composer ecosystem (directory /src) so the 4 prod deps and the dev tools
get advisory monitoring; noted the production-only vendor recommit step.

instructions/php-conventions + architecture-rules: rewritten to the
current Composer PSR-4 architecture. They previously described the
pre-migration state and misdirected Copilot:
- "No autoloading via Composer — custom src/autoload.php" (file removed)
  and "Do NOT introduce Composer dependencies" → Composer PSR-4, vendor
  committed production-only, dump-autoload workflow
- lowercase paths (src/cli, src/core, src/modules, …) → real PascalCase
  (src/Cli, src/Core, src/Modules, src/Streaming, …)
- setDb() / $r-prefix (both gone from the codebase) → DatabaseAware +
  self::db(); dropped the dead $r naming rule
- inverted namespace guidance → new code is namespaced; legacy coexists,
  don't mass-migrate
- dangling ARCHITECTURE.md ref → docs/en/development/architecture.md
  (which exists), src/config/modules.php path fixed
2026-08-07 20:11:26 +03:00
Divarion_D ef521b40a0 chore(agents): fix stale Composer/DI facts, trim broken memory boilerplate
The 6 kept subagents taught facts the codebase has since removed, and
each carried ~135 lines of duplicated memory-protocol boilerplate with a
broken hardcoded path (/media/divarion/... — this repo is /mnt/FILES/...).

Fact corrections (verified against the code):
- "no Composer / custom XC_Autoloader" → Composer PSR-4 (XcVm\ → src/),
  vendor/ committed production-only (XC_Autoloader no longer exists)
- setDb() static-injection DI → DatabaseAware trait + self::db()
  (self::db() in 34 files; setDb down to 1 legacy file; do not reintroduce)
- src/modules/{name}/ → src/Modules/{name}_{hash5}/, ns XcVm\Module\{Pascal}
- db-architect: MigratableInterface migrations → real file-based
  ModuleMigrator (database.sql + database_drop.sql + migrations/<semver>.sql)
- qa: dropped brittle "210/210" test count for the phpunit command
- global $db kept — it is accurately described as mid-migration

Memory block: replaced the boilerplate with a concise footer that points
at the correct relative .claude/agent-memory/<name>/ path and relies on
the `memory: project` frontmatter. Files shrank ~45%.
2026-08-07 19:54:37 +03:00
Divarion_D d2841aca0f chore(agents): prune redundant/unused subagents 13→6
Remove 7 subagents that were never used (empty agent-memory) and/or
overlapped heavily with the kept reviewers or built-in /code-review and
/security-review:

- ceo-team-coordinator, business-analyst, risk-officer — enterprise
  "consulting firm" roles that don't fit a solo-dev PHP IPTV panel
- solution-architect, technical-auditor — duplicate php-architect-reviewer
- performance-engineer, tech-doc-writer — niche, never invoked

Kept the 6 with proven use and distinct axes: backend-lead-reviewer,
security-architect, qa-lead-reviewer, devops-lead-reviewer,
php-architect-reviewer, db-architect.
2026-08-07 19:54:17 +03:00
Divarion_D 0f773b9758 refactor(streaming): extract map/scodec/source/HLS/FLV helpers with tests
Continue breaking up createChannelItem, startMovie and startStream by pulling
five self-contained blocks into pure, tested helpers:

- resolveOutputMap()          — VOD -map selection (custom > strip-subs > copy-all)
- subtitleCodecForContainer() — mp4->mov_text, mkv->srt, else copy
- resolveChannelSource()      — channel source string -> [serverId, path], rewriting
                                s:<server>:<path> to the remote getFile API URL
- buildHlsMpegtsOutput()      — HLS/mpegts segmenter output args
- buildFlvOutput()            — shared FLV output wrapper (RTMP relay + external
                                push, previously two identical lines)

The startStream extractions pass the conditional $rOptions/$rFLVOptions in as
parameters, so the control flow is unchanged. Behaviour preserved.

StreamProcessMovieOutputTest covers map precedence, container->codec mapping,
every source-resolution branch, HLS output assembly, and FLV wrapping.

Verified: php -l clean, make gates green, phpunit 360/360 green.
2026-08-07 19:31:18 +03:00
Divarion_D 0bb87452ad fix(streaming): import and map all VOD subtitles, not just the first
buildSubtitleImport nested the metadata loop inside the import loop and reused
the outer counter $i. The inner loop advanced $i to count(files), so the outer
import loop exited after its first iteration: only the first subtitle was
imported (-sub_charenc -i), while -map/-metadata was still emitted for every
file — mapping ffmpeg inputs that were never added. Multi-subtitle movies got a
single imported track plus dangling -map references (broken output).

Split the nested loop into two siblings — import every file, then map every
file — and cache the count. All configured subtitles are now imported and
mapped to the correct input index.

Add tests/Unit/StreamProcessSubtitleTest.php covering empty input, a single
local subtitle, remote-server fetch, and the multi-subtitle case that
reproduces the defect (import count was 1, must equal N). Verified red→green
against the pre-fix code.

Verified: php -l clean, make gates green, phpunit 336/336 green.
2026-08-07 19:04:16 +03:00
Divarion_D 4980b00829 refactor(streaming): extract buildSubtitleImport from startMovie
Move the VOD subtitle import + metadata assembly out of startMovie into a
private helper so the method is smaller and the subtitle logic is isolated.

Behaviour is preserved verbatim, INCLUDING a pre-existing bug: the inner
metadata loop reuses the outer import loop's $i counter, so the import loop
effectively runs once (first file) while metadata is mapped for all files.
Left as-is here; it is a real defect to fix in a dedicated change.

Verified: php -l clean, make gates green.
2026-08-07 18:56:00 +03:00
Divarion_D 7adf7a5b27 refactor(streaming): extract shared ffmpeg-command helpers in StreamProcess
createChannelItem, startMovie and startStream each inlined the same blocks
verbatim. Extract them into private helpers — removing the duplication and
shrinking the three oversized methods:

- buildLogoFilterOptions() — logo / -filter_complex overlay block (was inlined 3x)
- resolveGpuInputCodec()   — CUVID hardware-decoder detection (was inlined 2x)
- applyDefaultCopyCodecs() — default -acodec/-vcodec to stream copy (was inlined 3x)

Pure extraction, behaviour preserved. startStream's GPU block is intentionally
left inline: it reuses the already-computed $rFFProbeOutput instead of
re-probing the source, so it is not the same code.

Verified: php -l clean, make gates green (PSR-4 use-imports, LB manifest,
vendor prod-only). net -28 lines.
2026-08-07 18:51:07 +03:00
Divarion_D b98898b25e fix(streaming): reconnect LLOD http input to survive source drops 2026-08-07 16:54:08 +03:00
DanilandGitHub ecd3375497 Merge pull request #140 from Vateron-Media/fix/mpegts-delivery-throttle
fix(streaming): remove per-read throttle in live MPEG-TS delivery
2026-08-06 21:37:42 +03:00
DanilandGitHub 1d55f75f61 Merge branch 'main' into fix/mpegts-delivery-throttle 2026-08-06 21:33:03 +03:00
Divarion_D b83cb86fbb ci: run CI once per change (scope push to main, add concurrency) 2026-08-06 21:31:46 +03:00
Divarion_D 6d6aa6652e feat(tools): add stream_queue_check.py queue-integrity monitor
Standalone Python (stdlib-only) tool that verifies a stream delivers
segments correctly and its delivery queue does not break:

- HLS: EXT-X-MEDIA-SEQUENCE contiguity, no dropped/rewound segments, no
  EXT-X-DISCONTINUITY, every newly appearing segment downloadable.
- MPEG-TS: per-PID continuity_counter, sync-byte loss, TEI, delivery stalls,
  with a --tolerance for rare source glitches relayed by -c copy.
- --live: colored TUI dashboard modelling a virtual player — received
  timeline from PCR (TS) / EXTINF (HLS), playhead, and buffered cache
  seconds graphed over time.

Documented in docs/{en,ru}/development/streaming-subsystem.md.
2026-08-06 21:22:33 +03:00
Divarion_D 09001e595a fix(streaming): remove per-read throttle in live MPEG-TS delivery
The live TS delivery loop in stream/live.php slept 1 second after every
read, capping client throughput at read_buffer_size per second (8 KB/s
with the default 8192 buffer) — far below the stream bitrate. This
starved the client mid-segment and then dumped the segment remainder in
a burst (sawtooth delivery), and throttled behind/HD clients below their
bitrate so they could never catch up.

Drain available data without sleeping; only pause (1s) and tick the
stall counter when caught up to ffmpeg's write head. Delivery now paces
to the real bitrate regardless of read_buffer_size or channel bitrate.
This matches the already-correct pattern in admin/live.php.

Verified before/after on a live endpoint: the 8 KB/s dribble phase is
gone and each segment is delivered promptly.
2026-08-06 20:10:28 +03:00
Divarion_D f606371f2b update docs 2026-08-04 20:55:07 +03:00
DanilandGitHub 77f6ef056e Merge pull request #139 from Vateron-Media/dependabot/github_actions/actions/add-to-project-2.0.0
ci: bump actions/add-to-project from 1.0.2 to 2.0.0
2026-08-02 13:15:16 +03:00
dependabot[bot]andGitHub 7a09a11d84 ci: bump actions/add-to-project from 1.0.2 to 2.0.0
Bumps [actions/add-to-project](https://github.com/actions/add-to-project) from 1.0.2 to 2.0.0.
- [Release notes](https://github.com/actions/add-to-project/releases)
- [Commits](https://github.com/actions/add-to-project/compare/v1.0.2...v2.0.0)

---
updated-dependencies:
- dependency-name: actions/add-to-project
  dependency-version: 2.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-02 10:04:12 +00:00
Divarion_D 18cd757cc2 Prepare release 2.3.7 2026-08-02 11:55:34 +03:00
Divarion_D 837d8e4f0f Upd release checklist 2026-08-02 11:55:18 +03:00
Divarion_D 22e422bb1c fix(streams): report real transcode speed instead of a stuck "1x"
The Stream Info column always showed a transcode speed of "1x" even though
ffmpeg's real speed fluctuates. Two independent bugs were involved.

1. Progress was never captured while a stream ran.
   ffmpeg's `-progress` posted to the HTTP /progress endpoint, but ffmpeg
   holds one open-ended chunked POST for the stream's whole life. PHP-FPM's
   php://input can't read a length-less body, and nginx only invokes PHP
   once the request body is complete, so the endpoint fired only at stream
   end. `progress_info` therefore stayed empty and the view fell back to the
   hardcoded "1x".

   Switch ffmpeg to write `-progress` to a local file (the mechanism the
   created-channel path already uses). StreamsCronJob now tails that file,
   keeps the last complete report block, re-encodes it as the JSON the panel
   expects, and truncates it each cycle so it stays tiny on disk.

2. Speeds just above 1 were swallowed by the display.
   `floor($speed * 100) / 100` dropped e.g. 1.01 to "1x" because 1.01 * 100
   is 100.9999… in floating point. Use round() instead, and apply the same
   robust parsing to the radios path (which multiplied the "1.01x" string).

Files:
- Domain/Stream/StreamProcess.php   ffmpeg -progress -> local file
- Cli/CronJobs/StreamsCronJob.php    tail/parse/truncate the progress file
- Public/Controllers/Admin/TableController.php  round() speed display
2026-08-01 23:35:05 +03:00
Divarion_D c7db04396a Claude agents added. 2026-08-01 22:10:51 +03:00
Divarion_D 209fb59eb4 Fix (llod v2) Fixed mpegts segmentation when "On Demand" is enabled and llod v2 is selected 2026-08-01 19:50:59 +03:00
Divarion_D ffcfa9274b fix(reseller): populate activity log target column and fix footer scope
Reseller dashboard activity rows now resolve the target device/user
(line, user, mag, enigma) and render a link to it, falling back to
deleted_info for removed targets. Narrow the users_logs query to the
columns actually consumed and qualify the ORDER BY.

Fix renderUnifiedLayoutFooter so explicit page vars win over stale
globals and are also exposed in the footer's local scope; pass the
required vars from the reseller line/mag/enigma views.

Also fix broken quote nesting in the admin ASN table status buttons
that leaked literal quotes into the markup.
2026-08-01 17:28:42 +03:00
Divarion-D d1425ab957 fix(core): suppress image write failures instead of warning
@-suppress imagepng() and file_put_contents() for image caching; a failed write
is already handled by the surrounding file_exists checks, so the raw warning is
noise.
2026-07-30 19:47:06 +03:00
Divarion-D d410161806 fix(domain): null-safe reseller credit math and TMDb credits parsing
Default $rCost to 0 on non-charge paths (credit math and logs unchanged) and
guard TMDb cast/crew iteration with ?? [] so missing credits data no longer
triggers undefined-variable / foreach-on-null warnings.
2026-07-30 19:47:06 +03:00
Divarion-D 3b07de3026 fix(admin): null-safe table and view rendering
Use ?? on server status, divergence/series/name/user lookup maps, per-stream
server counts and movie property fields so admin tables and the movie edit form
render without undefined-key warnings when a row references data absent from the
supporting maps.
2026-07-30 19:47:06 +03:00
Divarion-D 6e59ec2ad7 fix(player-api): tolerate missing or cold stream cache files
Add readStreamCache() to safely read+igbinary-unserialize transient cache files,
returning null when absent or corrupt. Series/channel/VOD paths now skip or return
empty payloads instead of cascading into file_get_contents/offset-on-bool/
foreach-on-null warnings when a stream is deleted or its cache is not yet warmed.
2026-07-30 19:47:05 +03:00
Divarion-D 3e4fbae04c fix(stream): null-safe activity, stream and server lookups
Null-coalesce absent keys in activity info, cached signal counts, streams_servers
maps, server protocol and PID-running results, and @-suppress the stale .pid
unlink. Avoids offset-on-null/undefined-key warnings under PHP 8 without changing
behaviour on present data.
2026-07-30 19:47:05 +03:00
Divarion-D 2316c87628 fix(cli): guard cron jobs and commands against missing data and racing files
@-suppress unlink() of transient _errors/connection files that may already be
gone, tolerate non-array provider category/stream feeds, default absent category
ids to '', and bail early from ServersCronJob when SERVER_ID is not yet in the
servers map instead of dereferencing null.
2026-07-30 19:47:04 +03:00
Divarion-D f107e5f769 feat(navbar): make admin profile dropdown registry-driven
The top-right profile dropdown was a hardcoded HTML block in
  admin/header.php, so modules could not add or remove entries and the
  plex/watch "settings" links were baked into core.

  Move the menu into the NavbarRegistry: CoreNavbarProvider now registers
  the core items (edit profile, settings, backups, cache, modules, logout)
  under a reserved 'profile' parent, and header.php renders
  NavbarRegistry::getChildren('profile') adaptively. There is intentionally
  no top-level 'profile' node, so the items never leak into the main
  navigation. Order 100–980 is reserved for module-provided links.

  Extract NavbarRegistry::collapseDividers() to drop separators orphaned by
  permission filtering (leading, trailing, consecutive), and reuse the
  shared _xc_nav_visible()/_xc_nav_label() helpers by defining them once
  near the top of the header. Remove the hardcoded settings_plex /
  settings_watch entries — those now belong to their owning modules.

  Add NavbarProfileMenuTest covering collapseDividers, the core 'profile'
  contract (no top-level leak, edit first / logout last, permission gates),
  and the module-integration contract (reserved order slots, divider
  collapse when folder_watch_settings is absent).
2026-07-29 19:37:43 +03:00
Divarion-D 552c4036c9 fix(cron): reap wedged watchdog instead of trusting its presence
cron:servers only checked whether a watchdog process existed. A watchdog
  blocked in poll() on a half-open MariaDB socket (CLOSE_WAIT) inside its DB
  ping still exists, so cron kept trusting it indefinitely: last_check_ago
  went stale and the panel marked the node offline while nginx, php-fpm,
  redis and active streams were all healthy. Restarting only the watchdog
  restored the heartbeat immediately.

  Treat an abnormally old watchdog as stale. A normal generation lives only
  a few seconds, so any process alive for more than 90s is killed and a
  fresh generation is started; a plain presence check alone would keep
  trusting the wedged one forever.

  Add ProcessManager::getProcessAge(), which derives age from the mtime of
  the /proc/PID directory (time() - filemtime) — the same figure as
  `ps -o etimes` without shelling out, consistent with the rest of the class
  reading /proc directly and with no HZ/CLK_TCK assumption. Reaping uses the
  existing ProcessManager::kill() rather than a raw `kill -9`.

  Recovery restarts only the watchdog; nginx, php-fpm, redis, ffmpeg and
  running streams are untouched.
2026-07-29 18:43:27 +03:00
Divarion-D ebdcd6e725 Upd CODEOWNERS 2026-07-29 18:33:19 +03:00
Divarion-D 23009b3e6c Add workflow automation 2026-07-28 22:16:23 +03:00
Divarion-D f813645f0b Add template incident 2026-07-28 22:12:39 +03:00
Divarion-D ab6caf13e7 Fix (DB): Fixed overflow of maximum number of connections to the database 2026-07-28 21:08:13 +03:00
Divarion-D 12195c9e70 feat(workflow): add workflow_dispatch inputs for release notifications 2026-07-10 20:15:49 +03:00
Divarion-D d02827d4a0 Prepare release 2.3.6 2026-07-10 19:58:19 +03:00
Divarion-D b33e944cfd fix(cron): make daemon liveness checks precise so cron:servers actually revives them
Two false positives/negatives in process detection kept the panel's
self-healing loop dead on any real installation:

- isNginxRunning() looked for "nginx: master" only among xc_vm-owned
  processes, but the master runs as root on typical installs (workers run
  as xc_vm), so cron:servers/cron:streams bailed out with "XC_VM not
  running..." before reaching the daemon revival block. Now scans
  /proc/*/cmdline user-agnostically, same as RootSignalsCronJob.

- The per-daemon "is it alive" checks piped ps through grep by bare words:
  every live-stream ffmpeg carries -thread_queue_size/-max_muxing_queue_size
  in its command line, so the "queue" check matched any running stream and
  the encode queue daemon was never started while at least one channel was
  up — created channels sat at "0% DONE" until console.php queue was run by
  hand. All seven checks (signals, cache_handler, network, watchdog, queue,
  ondemand, scanner) now use ProcessManager::findProcessPIDs(), a /proc
  cmdline scan matching the daemon title (XC_VM[...]) or its exact
  console.php invocation. Kill branches use the same PID list — the old
  bare "ondemand"/"scanner" greps could kill an innocent ffmpeg whose
  source URL contained those words.
2026-07-10 19:36:15 +03:00
Divarion-D 603ee3c8b6 fix(streams): repair created-channel build chain and add live encode progress
- QueueCommand: adopt a live build PID instead of unlinking its .create
  marker and relaunching (which killed the running encoder and reset the
  build to 0% on every queue re-add); widen the PID capture window from
  0.3s to 5s to survive console.php bootstrap
- VodCronJob: check build liveness locally via /proc cmdline instead of an
  HTTP self-call that falsely reported the build dead whenever the internal
  API or server_online flag hiccuped
- CreatedCommand: verbose CLI output (per-source status, encode % / speed
  every 10s), local process checks instead of HTTP, cleanup of stale
  _.create on the nothing-to-build early exit
- StreamProcess: pass -progress <id>_<md5>.progress to the channel-item
  ffmpeg command; CreatedCommand parses it and mirrors the percentage into
  streams_servers.progress_info
- TableController/api.php: "% DONE" now includes fractional progress of the
  source currently being encoded
- MonitorCommand: stop type-3 (created) channels from falling through into
  the LLOD branch after startStream — LLOD cannot consume raw
  "s:<server>:<path>" sources and spammed "[LLOD] Invalid source" in a
  restart loop; the on-demand LLOD shortcut now also skips type 3
- PHP 8 warning fixes along the same chain: missing on_demand key
  (ChannelService), undefined $rSplit and missing parent_id column in
  grouped queries (TableController), missing .create file (VodCronJob),
  empty lines in _.list parsing and null cc_info (StreamProcess)
2026-07-10 19:19:25 +03:00
Divarion-D ab470f0203 fix(redis): correct method call for Redis configuration sync 2026-07-10 17:49:01 +03:00