Commit Graph
17 Commits
Author SHA1 Message Date
Divarion_D 16399dcc3d refactor(util): delete dead ImageUtils::resize() and generateThumbnail()
Both methods had zero references and were commented out on 2026-09-13
pending confirmation; remove them and their DEAD_CODE.md entries.
2026-09-25 21:33:05 +03:00
AbdoAhmedElbanaaandDivarion_D e264443909 fix(player-api): tolerate null bouquets and stream icon during player login
Port of Rosmi720/XC_VM@8f41d206. Harden the streaming user-info path against
null/malformed data that caused a fatal TypeError on player login:

- ImageUtils::validateURL() accepts null/empty (nullable icon columns) → ''.
- UserRepository::decodeUserFields() tolerates already-decoded arrays, null
  columns and malformed JSON (via a shared decodeJsonField helper).
- aggregateBouquetIds() skips non-array bouquet groups (mergeBouquetGroup
  helper); getStreamingUserInfo() resolves the bouquet map from the shared
  cache / DB when the caller passes none (resolveBouquets helper).
- PlayerApiController::getOutputFormats() guards a non-iterable input and
  falls back to the full format set.

Adapted to this tree: kept the existing null-safe category_map / active_cons
handling, and split the added guards into small covered helpers to stay within
the complexity ceiling (unit test for resolveBouquets).
2026-09-21 18:55:17 +03:00
9252836b05 fix(player-api): a channel without an icon took down the whole listing
The cs-fix pass (758a9cab) typed ImageUtils::validateURL()'s URL and
StreamSorter::formatTitle()'s title as non-nullable strings, but both
come from nullable columns (streams.stream_icon / stream_display_name,
streams_series.title / cover, …). get_live_streams passed a channel's
NULL stream_icon straight in, so one channel without an icon turned the
line's entire live list into a TypeError page — and the same for any of
the ~100 validateURL() callers (series covers, backdrops, episode
images, admin and reseller views) and a title-less stream or series.

Both now take null as '' (unit-tested). player_api also no longer hands
filterLoaded() a null when the categories cache file is missing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y4P9p5BXijMoGXd31tN6Zp
2026-09-18 09:57:17 +00:00
rootandClaude Opus 5 ee2f586a44 fix(streams): adding a stream without an icon failed
StreamService::process() runs the stream icon through
ImageUtils::downloadImage() when "download images" is on, and an empty icon
arrives there as null. The `string` type the cs-fix pass (758a9cab) put on
the parameter made that a TypeError, so saving a new stream with no icon
answered an empty page and created nothing. Series, movies, episodes, radios
and created channels hand it optional covers and backdrops the same way.

downloadImage() now takes null and hands back whatever it cannot download
unchanged, null included. Found by the new E2E stream test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WDhDajBPziJwjWZcXnh6R
2026-09-16 14:38:17 +00:00
Divarion_D dc7fa83b0a refactor: apply Rector safe sets + fix the transform's fallout (reviewed)
Ran `make rector-fix` (deadCode + codeQuality prepared sets) over the PSR-4
class trees (Core/Domain/Cli/Infrastructure). Net -600 lines: dead-code removal
and the empty-if/else collapse (the feedback_simplify_empty_else pattern this
adoption targeted). 99 files mechanically transformed.

The output was reviewed against the full test suite + PHPStan + a targeted scan;
this commit is the CORRECTED pass (no broken state in history):

- FIX (Rector bug): its boolean inversion dropped the parens around an
  assignment-in-condition — `if (($rKey = array_search(...)) === false)` became
  `if ($rKey = array_search(...) !== false)`, assigning the bool to $rKey and
  unsetting the wrong array offset. Restored parens in 7 sites (BouquetService,
  ChannelService, CategoryService). PHPStan caught only 1 of the 7; the rest
  were silent. Added BouquetServiceTest as a regression (proven to fail on the
  broken form).
- FIX (pre-existing, same class): GroupService::removeGroupFromUsers had the
  identical dropped-parens bug already in the tree — corrected here too.
- FIX: ServersCronJob::pingServer returns floor() (float) under an `: int`
  return type — added an (int) cast.
- ACCEPT: LocallyCalledStaticMethodToNonStaticRector converted 25 locally-called
  private static helpers to instance methods (behaviour-preserving; call sites
  rewritten). Updated MonitorCommandTest's reflection helper to invoke on a
  constructor-less instance.

Verified: PHPStan level 5 clean (0), suite 691 tests / 0 errors.

NOTE: do not re-run `make rector-fix` on this tree without first skipping the
inversion rule — the dropped-parens bug is deterministic and would return.
2026-09-13 17:27:42 +03:00
Divarion_D e5798ae951 chore(dead-code): comment out unused ImageUtils::resize/generateThumbnail + add index
Both methods have zero call sites anywhere under src/ (grep, excluding vendor).
Comment them out rather than delete (kept as a record), and start a dead-code
index (DEAD_CODE.md) tracking such symbols per file with the verification
command.

Also resolves the last PHPStan level-5 error: generateThumbnail contained an
unreachable 32x64 branch (type 5 is matched earlier); the whole method is dead
regardless, so commenting it out clears the finding. PHPStan is now clean.
2026-09-13 16:43:35 +03:00
Divarion_D 758a9cab0b style: apply K&R + tab formatting across the codebase (make cs-fix)
Mechanical, behaviour-preserving reformat produced by 'make cs-fix' under
the new build/phpcs.xml.dist ruleset: K&R braces, tab indentation, and the
other whitespace normalisations. No logic changes.
2026-09-13 14:14:23 +03:00
Divarion_D 71ccdac452 refactor: convert inline \XcVm\ FQNs to PSR-4 use imports
Replace fully-qualified \XcVm\... class references (in code and in
docblocks/@see/@param/@return/@throws) with short names backed by
top-of-file use imports, project-wide. Same-namespace references drop
the prefix with no import; view templates gain the top-level imports the
check-procedural-use gate expects. Purely mechanical, no behavior change.
2026-09-13 12:13:01 +03:00
Divarion_D 8f7055031c refactor(core): read settings via SettingsManager::get()
Replace SettingsManager::getAll()['key'] with SettingsManager::get('key') in the
core layer (dropbox_token, platform_api_key, api_pass, parse_type,
live_streaming_pass), including the `(string) (... ?? '')` sites in
ModuleManager where get()'s nullable return keeps the ?? fallback valid.
RequestManager::getAll() (request parameters) is left untouched.
2026-08-24 21:55:50 +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 50b408702a fix(images): create the images cache dir on demand in downloadImage
file_put_contents(IMAGES_PATH.…) failed with ENOENT on nodes where
  storage/images/ was never provisioned (e.g. an LB running the watch
  import), aborting the image cache and spamming warnings every cron tick.
  mkdir the directory (recursive, suppressed) before writing.
2026-07-07 22:01:50 +03:00
Divarion-D fc0fdb2f29 Fix documentation links in Reseller controllers and related classes to point to the correct GitHub repository URL. Remove unused directory registration code in autoload.php. 2026-06-25 20:32:18 +03:00
Divarion-D 9eec63937e style: import/namespace hygiene across src (PHP-CS-Fixer)
Apply 'make cs-fix' — 493 files. Mechanical, import-block only:
- sort use statements alphabetically (class/function/const grouped);
- drop imports left unused by the PSR-4 migration (e.g. classes referenced by
  leading-backslash FQCN whose redundant 'use' the automated insertion had added);
- one blank line after namespace and after the import block; collapse stray
  blank lines around use.

No logic changes. Verified: php -l clean; PHPStan no errors; PHPUnit 295/295; and a
temporary PHPStan pass over src/Public/Controllers confirms no still-referenced
import was removed (0 unresolved classes). 'use' after inline HTML in view
templates is valid and aliases correctly (verified) — those imports are sorted too.
2026-06-25 20:24:36 +03:00
Divarion-D 42d9ca8ea0 chore(psr4): phase 3 — namespace Domain layer
Namespace all of Domain into XcVm\Domain\<Subdir> (33 classes across Bouquet,
Device, Epg, Line, Security, Server, Stream, User, Vod).

- Add namespace to every Domain class; add use to referrers across src/ and
  tests/; convert the leading-backslash refs qualified in earlier Core commits
  (\UserRepository, \ServerRepository, \BouquetService, \CategoryService,
  \ConnectionTracker, \BlocklistService, ...) to their FQCNs.
- Qualify still-global / built-in deps inside Domain with leading backslash
  (\RedisManager, \TMDB, \WatchService, \FFprobeRunner, \ProcessChecker,
  \Exception, \DateTime, \PDO, ...) — Infrastructure/Streaming/module classes
  migrate later.
- BruteforceGuard: string guards class_exists('ServerRepository'/'BlocklistService')
  → ::class FQCN; drop the now-always-true method_exists check.
- phpstan-baseline.neon regenerated (292→291).

Verified: php -l clean; PHPStan no errors; PHPUnit 295/295; leading-backslash
re-sweep across Domain classes is clean.
2026-06-25 18:39:28 +03:00
Divarion-D da291e20f8 chore(psr4): phase 3 (Core) — namespace remaining Core subdirs
Namespace the rest of Core, completing the Core layer:
- Backup, Boundary, Cache (CacheInterface/FileCache/RedisCache), Diagnostics,
  GeoIP (GeoIPService/MaxMindUpdater), Init (LegacyInitializer), Localization
  (Translator), Process (Thread/Multithread/ProcessManager), Updates
  (GitHubReleases), Util (NetworkUtils, AdminHelpers, Encryption, GeoIP,
  ImageUtils/ImageResizeService, Mobile_Detect, StreamUtils, SystemInfo,
  TimeUtils), Validation (InputValidator) → XcVm\Core\<Subdir>.
- Rename GithubReleases.php → GitHubReleases.php so the file matches its class
  name (PSR-4 is case-sensitive); fix the WebApiBootstrap require accordingly.
- Qualify built-ins (\Exception, \DateTime, \DateTimeZone, \Redis,
  \RuntimeException, \BadMethodCallException, ...) and still-global deps
  (\ServerRepository, \CacheReader, \DatabaseFactory, \BouquetService,
  \CategoryService, \FfmpegPaths, \StreamSorter, \XC_VM). LegacyInitializer's
  Domain calls stay \-qualified (the known Core→Domain exception).
- Add use to referrers; fix leading-backslash refs from earlier commits; fix
  string class refs class_exists('Translator'/'NetworkUtils'/...) → ::class.
  Remove the duplicate global 'use BoundaryInterface;' in MinistraModule.
- phpstan-baseline.neon regenerated.

Core is now fully namespaced (procedural constant/error/RequestGuard files stay
global by design; M3uParser/PhpM3u8 remain vendored). Verified: php -l clean;
PHPStan no errors; PHPUnit 295/295; leading-backslash re-sweep clean.
2026-06-24 22:35:33 +03:00
Divarion-D 8ac1908554 chore(psr4): phase 3 (Core leaf) — namespace SettingsManager + SettingsRepository
Move the last two Core/Config classes into XcVm\Core\Config. SettingsManager
has the largest fan-out of the whole migration (referenced by ~224 files).

- Namespace SettingsManager (self-contained singleton, no class deps) and
  SettingsRepository (\FileCache:: qualified).
- Add 'use XcVm\Core\Config\SettingsManager;' to 224 referencing files and
  'use ...\SettingsRepository;' to 12 — call sites (SettingsManager::get(), etc.)
  unchanged. Done with a token-based inserter (after namespace/declare/<?php,
  idempotent, same-namespace files skipped).
- ToolsCommand::processRecaptcha: drop dead class_exists('SettingsManager') +
  method_exists guard (always autoloadable now) → call SettingsManager::clearCache()
  directly. This was the only string-literal class reference.

Core/Config is now fully namespaced (ConfigReader, DomainResolver, SettingsManager,
SettingsRepository); the procedural constant files (AppConfig/Binaries/Paths)
remain global by design.

Verified: php -l clean (226 files); PHPStan no errors (baseline unchanged — it is
line-independent so the added use-lines don't disturb it); PHPUnit 295/295; all
Config FQCNs resolve via Composer; sample Public referrers lint-clean.
2026-06-24 20:52:00 +03:00
Divarion-D 1a296d0985 chore(psr4): phase 1 — rename 7 top-level dirs to PascalCase
Atomic case-rename of the seven class-holding source directories to match the
PSR-4 namespace casing, plus every consequent path reference. No code logic
changes — pure structural rename. (config/content/resources/signals/migrations/
ministra/storage/tmp/vendor/www/bin stay lowercase.)

- git mv: core→Core, domain→Domain, infrastructure→Infrastructure,
  streaming→Streaming, modules→Modules, cli→Cli, public→Public (module subdirs
  like Modules/plex stay lowercase; loaded by ModuleLoader, not Composer).
- PHP filesystem paths updated across src/ + tests/: require/include, glob/scandir
  bases, view includes, asset/nginx-alias paths, autoload.php registerDirectories(),
  ModuleLoader/ModuleManager module roots, console.php discovery dirs.
- src/composer.json PSR-4 vendored-lib paths → Core/Parsing/...; vendor/ regenerated.
- nginx.conf: docroot + SCRIPT_FILENAME → Public/. SCRIPT_NAME and the public-facing
  /streaming/*.php compat routes are URLs, left unchanged.
- Build/CI: Makefile LB_DIRS / LB_DIRS_TO_REMOVE / LB_FILES_TO_REMOVE PascalCased
  (closes the LB-archive privileged-leak blocker); phpstan.dist.neon paths/
  scanDirectories/excludePaths; phpunit.xml.dist coverage; phpstan-baseline.neon
  regenerated (294→294 errors, no new resolution failures).
- migrations/deleted_files.txt: old lowercase trees listed for client cleanup
  (assumes case-sensitive FS — the supported Linux target).

Verified: grep-gate 0 live lowercase-dir require/include in src+tests; php -l clean;
PHPUnit 292/292; PHPStan no errors; Composer first / XC_Autoloader last in SPL stack;
global classes resolve from the renamed dirs.
2026-06-24 20:10:34 +03:00