- add PHPUnit bootstrap and config under tests/
- add focused unit tests for GitHubReleases, InputValidator and FfmpegPaths
- fix GitHubReleases cache file handling when switching update channel
- document PHPUnit PHAR usage and debug run commands in RU/EN docs
- document SFTP sync for tests/ and contributor test workflow
- remove broad smoke coverage approach in favor of per-file tests
- Move data queries, permission checks, and variable setup from views
into individual admin controllers (Controller → Service → Repository)
- Each controller now prepares $rViewData before rendering the view
- Controllers handle redirects, permission enforcement, and data loading
- Remove legacy \<?php if (!isset(\$__viewMode)): ?\> blocks from ~100 admin views
- Move data preparation logic to controllers/routes
- Update admin routes and AdminTableController
- Views now contain only HTML/template markup
- Move REST API dispatch block before login redirect to prevent
API access codes from being redirected to /login
- Add SessionController for admin session management
- Renumber index.php dispatch sections (3=REST API, 4=redirect)
- Change search string from 'cert not yet due for renewal' to
'not yet due for renewal' for compatibility with both Certbot 1.x
and Certbot 2.x (which says 'Certificate not yet due for renewal')
- Extract implode() to $rOutBlob variable
Replace separate install/update build targets with a single archive that
serves both purposes. The update script (src/update) now extracts to a
temp directory, removes excluded dirs (binaries, config, user data), and
copies remaining files over the live installation.
Changes:
- Remove main_update, lb_update, lb_update_copy_files,
main_update_copy_files Makefile targets and UPDATE_EXCLUDE_DIRS var
- Move exclude dirs list into src/update (Python) where filtering
actually happens at runtime
- Rewrite doUpdate() to use tempdir extraction with try/finally cleanup
- Make delete_files_list/lb_delete_files_list gracefully skip when
LAST_TAG is empty (warn instead of error)
- Simplify CI workflows: one make command per variant instead of
conditional install + update steps
- Add ARCHITECTURE.md §5.5 documenting update flow
- Update en/ru docs: update-system.md, updates_checklist.md
- Update makefile-build.instructions.md with new targets
- Translator::get() now returns English value (not raw key name)
when a key is missing in the current language
- addMissingKeyToAllLanguages() writes English value as placeholder
for non-English language files instead of key name
- Synced 800 missing keys from en.ini to all 6 language files
(bg, de, es, fr, pt, ru) with English values as editable placeholders
Extracted hardcoded English strings from admin panel views:
- Page titles: 33 new keys
- Labels: 203 new keys
- Table headers: 113 new keys
- Buttons: 47 new keys
- Tooltips/placeholders: 301 new keys
- JS alerts: 3 new keys
- Options/spans/misc: 103 new keys
Total: ~800 new translation keys (was 762, now 1528)
- ServersCronJob: guard against null watchdog_data from json_decode,
use ?? [] for cpu_average_array access
- UsersCronJob: safe json_decode for php_pids — check is_array()
before array_map to prevent TypeError on null
- CacheCronJob: suppress mkdir errors with @, check is_dir() before
chown/chgrp to handle permission-denied on LB servers
- settings.php: htmlspecialchars() array guard for api_ips, is_array()
guards for already-decoded allow_countries and allowed_stb_types
- api.php: null-safe parserelease title access, @var Database phpdoc
annotations for closures with use (&$db)
- movie.php: !empty() for RequestManager import key access
- MovieController.php: default variable declarations before compact(),
safe key access for direct_source and stream_status, proper movie
fetch with redirect on invalid id
- MovieService.php: null coalescing for movie_symlink, direct_proxy,
bouquet_create_list, category_create_list, bouquets, category_id
- Fix TmdbClient constructor require path for config.php
- Update all include_once paths to use __DIR__ relative paths
- Move files from nested config/config/ and roles/roles/ to correct locations
- Remove duplicate files from old incorrect paths
When a domain is configured but not resolving (DNS not set up, cert not active),
stream redirect URLs use the domain causing playback to fail. Now:
- StreamRedirector::getStreamingURL() falls back to server_ip when client
connects via IP address (HOST is an IP)
- DomainResolver::resolve() preserves IP when use_mdomain_in_lists=1 but
client accessed via IP address
- Introduced a new common.js file containing essential functions for admin page operations.
- Implemented utilities for modal handling, error/success notifications, domain/IP validation, session management, and SPA navigation.
- Added functions for managing tooltips, search functionality, and URL parameter manipulation.
- Enhanced user experience with toast notifications and modal interactions.
- Updated the XC_Bootstrap class to include the EventDispatcher class in the service container.
- Modified the ModuleLoader class to utilize the EventDispatcher for subscribing to events, enhancing the event handling mechanism.