diff --git a/Makefile b/Makefile index fb3f4836..75d9f4d5 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,7 @@ LB_DIRS_TO_REMOVE := \ Public/Views \ Public/assets \ Public/routes \ + Core/Reference \ resources/langs \ resources/libs @@ -75,6 +76,9 @@ LB_FILES_TO_REMOVE := \ Cli/CronJobs/ProvidersCronJob.php \ Cli/CronJobs/SeriesCronJob.php \ Domain/Epg/EPG.php \ + Core/Enum/Theme.php \ + Core/Enum/ResellerAction.php \ + Core/Enum/ClientFilter.php \ bin/nginx/conf/gzip.conf EXCLUDE_ARGS := $(addprefix --exclude=,$(EXCLUDES)) diff --git a/src/Core/Enum/ClientFilter.php b/src/Core/Enum/ClientFilter.php new file mode 100644 index 00000000..93537a57 --- /dev/null +++ b/src/Core/Enum/ClientFilter.php @@ -0,0 +1,103 @@ + label map) with a + * string-backed enum. The backing value equals the legacy array key (the + * `client_status` column persisted in the client request log). + * + * @package XC_VM_Core_Enum + * @author Divarion_D + * @copyright 2025-2026 Vateron Media + * @link https://github.com/Vateron-Media/XC_VM + * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html + */ +enum ClientFilter: string { + case LbTokenInvalid = 'LB_TOKEN_INVALID'; + case NotInBouquet = 'NOT_IN_BOUQUET'; + case BlockedAsn = 'BLOCKED_ASN'; + case IspLockFailed = 'ISP_LOCK_FAILED'; + case UserDisallowExt = 'USER_DISALLOW_EXT'; + case AuthFailed = 'AUTH_FAILED'; + case UserExpired = 'USER_EXPIRED'; + case UserDisabled = 'USER_DISABLED'; + case UserBan = 'USER_BAN'; + case MagTokenInvalid = 'MAG_TOKEN_INVALID'; + case StalkerChannelMismatch = 'STALKER_CHANNEL_MISMATCH'; + case StalkerIpMismatch = 'STALKER_IP_MISMATCH'; + case StalkerKeyExpired = 'STALKER_KEY_EXPIRED'; + case StalkerDecryptFailed = 'STALKER_DECRYPT_FAILED'; + case EmptyUa = 'EMPTY_UA'; + case IpBan = 'IP_BAN'; + case CountryDisallow = 'COUNTRY_DISALLOW'; + case UserAgentBan = 'USER_AGENT_BAN'; + case UserAlreadyConnected = 'USER_ALREADY_CONNECTED'; + case RestreamDetect = 'RESTREAM_DETECT'; + case ProxyDetect = 'PROXY_DETECT'; + case HostingDetect = 'HOSTING_DETECT'; + case LineCreateFail = 'LINE_CREATE_FAIL'; + case ConnectionLoop = 'CONNECTION_LOOP'; + case TokenExpired = 'TOKEN_EXPIRED'; + case IpMismatch = 'IP_MISMATCH'; + + /** + * Human-readable filter label (as shown in the client request log). + */ + public function label(): string { + return match ($this) { + self::LbTokenInvalid => 'Token Failure', + self::NotInBouquet => 'Not in Bouquet', + self::BlockedAsn => 'Blocked ASN', + self::IspLockFailed => 'ISP Lock Failed', + self::UserDisallowExt => 'Extension Disallowed', + self::AuthFailed => 'Authentication Failed', + self::UserExpired => 'User Expired', + self::UserDisabled => 'User Disabled', + self::UserBan => 'User Banned', + self::MagTokenInvalid => 'MAG Token Invalid', + self::StalkerChannelMismatch => 'Stalker Channel Mismatch', + self::StalkerIpMismatch => 'Stalker IP Mismatch', + self::StalkerKeyExpired => 'Stalker Key Expired', + self::StalkerDecryptFailed => 'Stalker Decrypt Failed', + self::EmptyUa => 'Empty User-Agent', + self::IpBan => 'IP Banned', + self::CountryDisallow => 'Country Disallowed', + self::UserAgentBan => 'User-Agent Disallowed', + self::UserAlreadyConnected => 'IP Limit Reached', + self::RestreamDetect => 'Restream Detected', + self::ProxyDetect => 'Proxy / VPN Detected', + self::HostingDetect => 'Hosting Server Detected', + self::LineCreateFail => 'Connection Failed', + self::ConnectionLoop => 'Connection Loop', + self::TokenExpired => 'Token Expired', + self::IpMismatch => 'IP Mismatch', + }; + } + + /** + * Resolve a raw status key to its label, falling back to the raw key + * itself when it is unknown (tolerant lookup for log rendering). + */ + public static function labelFor(string $key): string { + return self::tryFrom($key)?->label() ?? $key; + } + + /** + * Ordered key => label map for building select/filter dropdowns, + * preserving the legacy `$rClientFilters` ordering. + * + * @return array + */ + public static function options(): array { + $options = []; + foreach (self::cases() as $case) { + $options[$case->value] = $case->label(); + } + return $options; + } +} diff --git a/src/Core/Enum/ResellerAction.php b/src/Core/Enum/ResellerAction.php new file mode 100644 index 00000000..7d0e4751 --- /dev/null +++ b/src/Core/Enum/ResellerAction.php @@ -0,0 +1,61 @@ + label map) with + * a string-backed enum. The backing value equals the legacy array key + * (the `action` column persisted in the reseller log). + * + * @package XC_VM_Core_Enum + * @author Divarion_D + * @copyright 2025-2026 Vateron Media + * @link https://github.com/Vateron-Media/XC_VM + * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html + */ +enum ResellerAction: string { + case New = 'new'; + case Extend = 'extend'; + case Convert = 'convert'; + case Edit = 'edit'; + case Enable = 'enable'; + case Disable = 'disable'; + case Delete = 'delete'; + case SendEvent = 'send_event'; + case AdjustCredits = 'adjust_credits'; + + /** + * Human-readable action label (as shown in log filters). + */ + public function label(): string { + return match ($this) { + self::New => 'Create', + self::Extend => 'Extend', + self::Convert => 'Convert', + self::Edit => 'Edit', + self::Enable => 'Enable', + self::Disable => 'Disable', + self::Delete => 'Delete', + self::SendEvent => 'MAG Event', + self::AdjustCredits => 'Adjust Credits', + }; + } + + /** + * Ordered key => label map for building select/filter dropdowns, + * preserving the legacy `$rResellerActions` ordering. + * + * @return array + */ + public static function options(): array { + $options = []; + foreach (self::cases() as $case) { + $options[$case->value] = $case->label(); + } + return $options; + } +} diff --git a/src/Core/Enum/Theme.php b/src/Core/Enum/Theme.php new file mode 100644 index 00000000..e0a0d179 --- /dev/null +++ b/src/Core/Enum/Theme.php @@ -0,0 +1,68 @@ + ..., 'dark' => ..., 'image' => ...]` rows) with an + * exhaustive enum. The backing int equals the legacy array index, so + * existing `profile.theme` values map straight through Theme::fromId(). + * + * @package XC_VM_Core_Enum + * @author Divarion_D + * @copyright 2025-2026 Vateron Media + * @link https://github.com/Vateron-Media/XC_VM + * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html + */ +enum Theme: int { + /** Default light theme. */ + case Light = 0; + + /** Dark theme. */ + case Dark = 1; + + /** + * Return true when this theme renders the dark layout variant. + */ + public function isDark(): bool { + return $this === self::Dark; + } + + /** + * Human-readable theme name (as shown in the profile selector). + */ + public function label(): string { + return match ($this) { + self::Light => 'Light', + self::Dark => 'Dark', + }; + } + + /** + * Resolve a stored profile theme value to a Theme, defaulting to Light + * for missing or out-of-range values. + * + * @param mixed $id The raw `theme` value from the user profile. + */ + public static function fromId(mixed $id): self { + return self::tryFrom((int) $id) ?? self::Light; + } + + /** + * Ordered id => label map for building the theme selector, preserving + * the legacy `$rThemes` ordering (0 => Light, 1 => Dark). + * + * @return array + */ + public static function options(): array { + $options = []; + foreach (self::cases() as $case) { + $options[$case->value] = $case->label(); + } + return $options; + } +} diff --git a/src/Core/Reference/DeviceReference.php b/src/Core/Reference/DeviceReference.php new file mode 100644 index 00000000..fcf77010 --- /dev/null +++ b/src/Core/Reference/DeviceReference.php @@ -0,0 +1,31 @@ + + * @copyright 2025-2026 Vateron Media + * @link https://github.com/Vateron-Media/XC_VM + * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html + */ +final class DeviceReference { + /** Supported MAG / Aura STB model identifiers. */ + private const MAG_MODELS = array('AuraHD', 'AuraHD2', 'AuraHD3', 'AuraHD4', 'AuraHD5', 'AuraHD6', 'AuraHD7', 'AuraHD8', 'AuraHD9', 'MAG200', 'MAG245', 'MAG245D', 'MAG250', 'MAG254', 'MAG255', 'MAG256', 'MAG257', 'MAG260', 'MAG270', 'MAG275', 'MAG322', 'MAG323', 'MAG324', 'MAG325', 'MAG349', 'MAG350', 'MAG351', 'MAG352', 'MAG420', 'WR320', 'TH100', 'MAG424', 'MAG424W3'); + + /** + * Supported MAG / Aura STB model identifiers. + * + * @return array + */ + public static function magModels(): array { + return self::MAG_MODELS; + } +} diff --git a/src/Core/Reference/GeoReference.php b/src/Core/Reference/GeoReference.php new file mode 100644 index 00000000..1fa52a6e --- /dev/null +++ b/src/Core/Reference/GeoReference.php @@ -0,0 +1,58 @@ + + * @copyright 2025-2026 Vateron Media + * @link https://github.com/Vateron-Media/XC_VM + * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html + */ +final class GeoReference { + /** ISO 3166-1 alpha-2 code => official country name. */ + private const COUNTRY_CODES = array('AF' => 'Afghanistan', 'AL' => 'Albania', 'DZ' => 'Algeria', 'AS' => 'American Samoa', 'AD' => 'Andorra', 'AO' => 'Angola', 'AI' => 'Anguilla', 'AQ' => 'Antarctica', 'AG' => 'Antigua and Barbuda', 'AR' => 'Argentina', 'AM' => 'Armenia', 'AW' => 'Aruba', 'AU' => 'Australia', 'AT' => 'Austria', 'AZ' => 'Azerbaijan', 'BS' => 'Bahamas', 'BH' => 'Bahrain', 'BD' => 'Bangladesh', 'BB' => 'Barbados', 'BY' => 'Belarus', 'BE' => 'Belgium', 'BZ' => 'Belize', 'BJ' => 'Benin', 'BM' => 'Bermuda', 'BT' => 'Bhutan', 'BO' => 'Bolivia (Plurinational State of)', 'BQ' => 'Bonaire, Sint Eustatius and Saba', 'BA' => 'Bosnia and Herzegovina', 'BW' => 'Botswana', 'BV' => 'Bouvet Island', 'BR' => 'Brazil', 'IO' => 'British Indian Ocean Territory', 'BN' => 'Brunei Darussalam', 'BG' => 'Bulgaria', 'BF' => 'Burkina Faso', 'BI' => 'Burundi', 'CV' => 'Cabo Verde', 'KH' => 'Cambodia', 'CM' => 'Cameroon', 'CA' => 'Canada', 'KY' => 'Cayman Islands', 'CF' => 'Central African Republic', 'TD' => 'Chad', 'CL' => 'Chile', 'CN' => 'China', 'CX' => 'Christmas Island', 'CC' => 'Cocos (Keeling) Islands', 'CO' => 'Colombia', 'KM' => 'Comoros', 'CD' => 'Congo (the Democratic Republic of the)', 'CG' => 'Congo', 'CK' => 'Cook Islands', 'CR' => 'Costa Rica', 'HR' => 'Croatia', 'CU' => 'Cuba', 'CW' => 'Curaçao', 'CY' => 'Cyprus', 'CZ' => 'Czechia', 'CI' => "Côte d'Ivoire", 'DK' => 'Denmark', 'DJ' => 'Djibouti', 'DM' => 'Dominica', 'DO' => 'Dominican Republic', 'EC' => 'Ecuador', 'EG' => 'Egypt', 'SV' => 'El Salvador', 'GQ' => 'Equatorial Guinea', 'ER' => 'Eritrea', 'EE' => 'Estonia', 'SZ' => 'Eswatini', 'ET' => 'Ethiopia', 'FK' => 'Falkland Islands [Malvinas]', 'FO' => 'Faroe Islands', 'FJ' => 'Fiji', 'FI' => 'Finland', 'FR' => 'France', 'GF' => 'French Guiana', 'PF' => 'French Polynesia', 'TF' => 'French Southern Territories', 'GA' => 'Gabon', 'GM' => 'Gambia', 'GE' => 'Georgia', 'DE' => 'Germany', 'GH' => 'Ghana', 'GI' => 'Gibraltar', 'GR' => 'Greece', 'GL' => 'Greenland', 'GD' => 'Grenada', 'GP' => 'Guadeloupe', 'GU' => 'Guam', 'GT' => 'Guatemala', 'GG' => 'Guernsey', 'GN' => 'Guinea', 'GW' => 'Guinea-Bissau', 'GY' => 'Guyana', 'HT' => 'Haiti', 'HM' => 'Heard Island and McDonald Islands', 'VA' => 'Holy See', 'HN' => 'Honduras', 'HK' => 'Hong Kong', 'HU' => 'Hungary', 'IS' => 'Iceland', 'IN' => 'India', 'ID' => 'Indonesia', 'IR' => 'Iran (Islamic Republic of)', 'IQ' => 'Iraq', 'IE' => 'Ireland', 'IM' => 'Isle of Man', 'IL' => 'Israel', 'IT' => 'Italy', 'JM' => 'Jamaica', 'JP' => 'Japan', 'JE' => 'Jersey', 'JO' => 'Jordan', 'KZ' => 'Kazakhstan', 'KE' => 'Kenya', 'KI' => 'Kiribati', 'KP' => "Korea (the Democratic People's Republic of)", 'KR' => 'Korea (the Republic of)', 'KW' => 'Kuwait', 'KG' => 'Kyrgyzstan', 'LA' => "Lao People's Democratic Republic", 'LV' => 'Latvia', 'LB' => 'Lebanon', 'LS' => 'Lesotho', 'LR' => 'Liberia', 'LY' => 'Libya', 'LI' => 'Liechtenstein', 'LT' => 'Lithuania', 'LU' => 'Luxembourg', 'MO' => 'Macao', 'MG' => 'Madagascar', 'MW' => 'Malawi', 'MY' => 'Malaysia', 'MV' => 'Maldives', 'ML' => 'Mali', 'MT' => 'Malta', 'MH' => 'Marshall Islands', 'MQ' => 'Martinique', 'MR' => 'Mauritania', 'MU' => 'Mauritius', 'YT' => 'Mayotte', 'MX' => 'Mexico', 'FM' => 'Micronesia (Federated States of)', 'MD' => 'Moldova (the Republic of)', 'MC' => 'Monaco', 'MN' => 'Mongolia', 'ME' => 'Montenegro', 'MS' => 'Montserrat', 'MA' => 'Morocco', 'MZ' => 'Mozambique', 'MM' => 'Myanmar', 'NA' => 'Namibia', 'NR' => 'Nauru', 'NP' => 'Nepal', 'NL' => 'Netherlands', 'NC' => 'New Caledonia', 'NZ' => 'New Zealand', 'NI' => 'Nicaragua', 'NE' => 'Niger', 'NG' => 'Nigeria', 'NU' => 'Niue', 'NF' => 'Norfolk Island', 'MP' => 'Northern Mariana Islands', 'NO' => 'Norway', 'OM' => 'Oman', 'PK' => 'Pakistan', 'PW' => 'Palau', 'PS' => 'Palestine, State of', 'PA' => 'Panama', 'PG' => 'Papua New Guinea', 'PY' => 'Paraguay', 'PE' => 'Peru', 'PH' => 'Philippines', 'PN' => 'Pitcairn', 'PL' => 'Poland', 'PT' => 'Portugal', 'PR' => 'Puerto Rico', 'QA' => 'Qatar', 'MK' => 'Republic of North Macedonia', 'RO' => 'Romania', 'RU' => 'Russian Federation', 'RW' => 'Rwanda', 'RE' => 'Réunion', 'BL' => 'Saint Barthélemy', 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', 'KN' => 'Saint Kitts and Nevis', 'LC' => 'Saint Lucia', 'MF' => 'Saint Martin (French part)', 'PM' => 'Saint Pierre and Miquelon', 'VC' => 'Saint Vincent and the Grenadines', 'WS' => 'Samoa', 'SM' => 'San Marino', 'ST' => 'Sao Tome and Principe', 'SA' => 'Saudi Arabia', 'SN' => 'Senegal', 'RS' => 'Serbia', 'SC' => 'Seychelles', 'SL' => 'Sierra Leone', 'SG' => 'Singapore', 'SX' => 'Sint Maarten (Dutch part)', 'SK' => 'Slovakia', 'SI' => 'Slovenia', 'SB' => 'Solomon Islands', 'SO' => 'Somalia', 'ZA' => 'South Africa', 'GS' => 'South Georgia and the South Sandwich Islands', 'SS' => 'South Sudan', 'ES' => 'Spain', 'LK' => 'Sri Lanka', 'SD' => 'Sudan', 'SR' => 'Suriname', 'SJ' => 'Svalbard and Jan Mayen', 'SE' => 'Sweden', 'CH' => 'Switzerland', 'SY' => 'Syrian Arab Republic', 'TW' => 'Taiwan (Province of China)', 'TJ' => 'Tajikistan', 'TZ' => 'Tanzania, United Republic of', 'TH' => 'Thailand', 'TL' => 'Timor-Leste', 'TG' => 'Togo', 'TK' => 'Tokelau', 'TO' => 'Tonga', 'TT' => 'Trinidad and Tobago', 'TN' => 'Tunisia', 'TR' => 'Turkey', 'TM' => 'Turkmenistan', 'TC' => 'Turks and Caicos Islands', 'TV' => 'Tuvalu', 'UG' => 'Uganda', 'UA' => 'Ukraine', 'AE' => 'United Arab Emirates', 'GB' => 'United Kingdom', 'UM' => 'United States Minor Outlying Islands', 'US' => 'United States of America', 'UY' => 'Uruguay', 'UZ' => 'Uzbekistan', 'VU' => 'Vanuatu', 'VE' => 'Venezuela (Bolivarian Republic of)', 'VN' => 'Viet Nam', 'VG' => 'Virgin Islands (British)', 'VI' => 'Virgin Islands (U.S.)', 'WF' => 'Wallis and Futuna', 'EH' => 'Western Sahara', 'YE' => 'Yemen', 'ZM' => 'Zambia', 'ZW' => 'Zimbabwe', 'AX' => 'Åland Islands'); + + /** Ordered list of `['id' => code, 'name' => label]` rows (blocking dropdown; "Off" first). */ + private const COUNTRIES = array(array('id' => '', 'name' => 'Off'), array('id' => 'A1', 'name' => 'Anonymous Proxy'), array('id' => 'A2', 'name' => 'Satellite Provider'), array('id' => 'O1', 'name' => 'Other Country'), array('id' => 'AF', 'name' => 'Afghanistan'), array('id' => 'AX', 'name' => 'Aland Islands'), array('id' => 'AL', 'name' => 'Albania'), array('id' => 'DZ', 'name' => 'Algeria'), array('id' => 'AS', 'name' => 'American Samoa'), array('id' => 'AD', 'name' => 'Andorra'), array('id' => 'AO', 'name' => 'Angola'), array('id' => 'AI', 'name' => 'Anguilla'), array('id' => 'AQ', 'name' => 'Antarctica'), array('id' => 'AG', 'name' => 'Antigua And Barbuda'), array('id' => 'AR', 'name' => 'Argentina'), array('id' => 'AM', 'name' => 'Armenia'), array('id' => 'AW', 'name' => 'Aruba'), array('id' => 'AU', 'name' => 'Australia'), array('id' => 'AT', 'name' => 'Austria'), array('id' => 'AZ', 'name' => 'Azerbaijan'), array('id' => 'BS', 'name' => 'Bahamas'), array('id' => 'BH', 'name' => 'Bahrain'), array('id' => 'BD', 'name' => 'Bangladesh'), array('id' => 'BB', 'name' => 'Barbados'), array('id' => 'BY', 'name' => 'Belarus'), array('id' => 'BE', 'name' => 'Belgium'), array('id' => 'BZ', 'name' => 'Belize'), array('id' => 'BJ', 'name' => 'Benin'), array('id' => 'BM', 'name' => 'Bermuda'), array('id' => 'BT', 'name' => 'Bhutan'), array('id' => 'BO', 'name' => 'Bolivia'), array('id' => 'BA', 'name' => 'Bosnia And Herzegovina'), array('id' => 'BW', 'name' => 'Botswana'), array('id' => 'BV', 'name' => 'Bouvet Island'), array('id' => 'BR', 'name' => 'Brazil'), array('id' => 'IO', 'name' => 'British Indian Ocean Territory'), array('id' => 'BN', 'name' => 'Brunei Darussalam'), array('id' => 'BG', 'name' => 'Bulgaria'), array('id' => 'BF', 'name' => 'Burkina Faso'), array('id' => 'BI', 'name' => 'Burundi'), array('id' => 'KH', 'name' => 'Cambodia'), array('id' => 'CM', 'name' => 'Cameroon'), array('id' => 'CA', 'name' => 'Canada'), array('id' => 'CV', 'name' => 'Cape Verde'), array('id' => 'KY', 'name' => 'Cayman Islands'), array('id' => 'CF', 'name' => 'Central African Republic'), array('id' => 'TD', 'name' => 'Chad'), array('id' => 'CL', 'name' => 'Chile'), array('id' => 'CN', 'name' => 'China'), array('id' => 'CX', 'name' => 'Christmas Island'), array('id' => 'CC', 'name' => 'Cocos (Keeling) Islands'), array('id' => 'CO', 'name' => 'Colombia'), array('id' => 'KM', 'name' => 'Comoros'), array('id' => 'CG', 'name' => 'Congo'), array('id' => 'CD', 'name' => 'Congo, Democratic Republic'), array('id' => 'CK', 'name' => 'Cook Islands'), array('id' => 'CR', 'name' => 'Costa Rica'), array('id' => 'CI', 'name' => "Cote D'Ivoire"), array('id' => 'HR', 'name' => 'Croatia'), array('id' => 'CU', 'name' => 'Cuba'), array('id' => 'CY', 'name' => 'Cyprus'), array('id' => 'CZ', 'name' => 'Czech Republic'), array('id' => 'DK', 'name' => 'Denmark'), array('id' => 'DJ', 'name' => 'Djibouti'), array('id' => 'DM', 'name' => 'Dominica'), array('id' => 'DO', 'name' => 'Dominican Republic'), array('id' => 'EC', 'name' => 'Ecuador'), array('id' => 'EG', 'name' => 'Egypt'), array('id' => 'SV', 'name' => 'El Salvador'), array('id' => 'GQ', 'name' => 'Equatorial Guinea'), array('id' => 'ER', 'name' => 'Eritrea'), array('id' => 'EE', 'name' => 'Estonia'), array('id' => 'ET', 'name' => 'Ethiopia'), array('id' => 'FK', 'name' => 'Falkland Islands (Malvinas)'), array('id' => 'FO', 'name' => 'Faroe Islands'), array('id' => 'FJ', 'name' => 'Fiji'), array('id' => 'FI', 'name' => 'Finland'), array('id' => 'FR', 'name' => 'France'), array('id' => 'GF', 'name' => 'French Guiana'), array('id' => 'PF', 'name' => 'French Polynesia'), array('id' => 'TF', 'name' => 'French Southern Territories'), array('id' => 'MK', 'name' => 'Fyrom'), array('id' => 'GA', 'name' => 'Gabon'), array('id' => 'GM', 'name' => 'Gambia'), array('id' => 'GE', 'name' => 'Georgia'), array('id' => 'DE', 'name' => 'Germany'), array('id' => 'GH', 'name' => 'Ghana'), array('id' => 'GI', 'name' => 'Gibraltar'), array('id' => 'GR', 'name' => 'Greece'), array('id' => 'GL', 'name' => 'Greenland'), array('id' => 'GD', 'name' => 'Grenada'), array('id' => 'GP', 'name' => 'Guadeloupe'), array('id' => 'GU', 'name' => 'Guam'), array('id' => 'GT', 'name' => 'Guatemala'), array('id' => 'GG', 'name' => 'Guernsey'), array('id' => 'GN', 'name' => 'Guinea'), array('id' => 'GW', 'name' => 'Guinea-Bissau'), array('id' => 'GY', 'name' => 'Guyana'), array('id' => 'HT', 'name' => 'Haiti'), array('id' => 'HM', 'name' => 'Heard Island & Mcdonald Islands'), array('id' => 'VA', 'name' => 'Holy See (Vatican City State)'), array('id' => 'HN', 'name' => 'Honduras'), array('id' => 'HK', 'name' => 'Hong Kong'), array('id' => 'HU', 'name' => 'Hungary'), array('id' => 'IS', 'name' => 'Iceland'), array('id' => 'IN', 'name' => 'India'), array('id' => 'ID', 'name' => 'Indonesia'), array('id' => 'IR', 'name' => 'Iran, Islamic Republic Of'), array('id' => 'IQ', 'name' => 'Iraq'), array('id' => 'IE', 'name' => 'Ireland'), array('id' => 'IM', 'name' => 'Isle Of Man'), array('id' => 'IL', 'name' => 'Israel'), array('id' => 'IT', 'name' => 'Italy'), array('id' => 'JM', 'name' => 'Jamaica'), array('id' => 'JP', 'name' => 'Japan'), array('id' => 'JE', 'name' => 'Jersey'), array('id' => 'JO', 'name' => 'Jordan'), array('id' => 'KZ', 'name' => 'Kazakhstan'), array('id' => 'KE', 'name' => 'Kenya'), array('id' => 'KI', 'name' => 'Kiribati'), array('id' => 'KR', 'name' => 'Korea'), array('id' => 'KW', 'name' => 'Kuwait'), array('id' => 'KG', 'name' => 'Kyrgyzstan'), array('id' => 'LA', 'name' => "Lao People's Democratic Republic"), array('id' => 'LV', 'name' => 'Latvia'), array('id' => 'LB', 'name' => 'Lebanon'), array('id' => 'LS', 'name' => 'Lesotho'), array('id' => 'LR', 'name' => 'Liberia'), array('id' => 'LY', 'name' => 'Libyan Arab Jamahiriya'), array('id' => 'LI', 'name' => 'Liechtenstein'), array('id' => 'LT', 'name' => 'Lithuania'), array('id' => 'LU', 'name' => 'Luxembourg'), array('id' => 'MO', 'name' => 'Macao'), array('id' => 'MG', 'name' => 'Madagascar'), array('id' => 'MW', 'name' => 'Malawi'), array('id' => 'MY', 'name' => 'Malaysia'), array('id' => 'MV', 'name' => 'Maldives'), array('id' => 'ML', 'name' => 'Mali'), array('id' => 'MT', 'name' => 'Malta'), array('id' => 'MH', 'name' => 'Marshall Islands'), array('id' => 'MQ', 'name' => 'Martinique'), array('id' => 'MR', 'name' => 'Mauritania'), array('id' => 'MU', 'name' => 'Mauritius'), array('id' => 'YT', 'name' => 'Mayotte'), array('id' => 'MX', 'name' => 'Mexico'), array('id' => 'FM', 'name' => 'Micronesia, Federated States Of'), array('id' => 'MD', 'name' => 'Moldova'), array('id' => 'MC', 'name' => 'Monaco'), array('id' => 'MN', 'name' => 'Mongolia'), array('id' => 'ME', 'name' => 'Montenegro'), array('id' => 'MS', 'name' => 'Montserrat'), array('id' => 'MA', 'name' => 'Morocco'), array('id' => 'MZ', 'name' => 'Mozambique'), array('id' => 'MM', 'name' => 'Myanmar'), array('id' => 'NA', 'name' => 'Namibia'), array('id' => 'NR', 'name' => 'Nauru'), array('id' => 'NP', 'name' => 'Nepal'), array('id' => 'NL', 'name' => 'Netherlands'), array('id' => 'AN', 'name' => 'Netherlands Antilles'), array('id' => 'NC', 'name' => 'New Caledonia'), array('id' => 'NZ', 'name' => 'New Zealand'), array('id' => 'NI', 'name' => 'Nicaragua'), array('id' => 'NE', 'name' => 'Niger'), array('id' => 'NG', 'name' => 'Nigeria'), array('id' => 'NU', 'name' => 'Niue'), array('id' => 'NF', 'name' => 'Norfolk Island'), array('id' => 'MP', 'name' => 'Northern Mariana Islands'), array('id' => 'NO', 'name' => 'Norway'), array('id' => 'OM', 'name' => 'Oman'), array('id' => 'PK', 'name' => 'Pakistan'), array('id' => 'PW', 'name' => 'Palau'), array('id' => 'PS', 'name' => 'Palestinian Territory, Occupied'), array('id' => 'PA', 'name' => 'Panama'), array('id' => 'PG', 'name' => 'Papua New Guinea'), array('id' => 'PY', 'name' => 'Paraguay'), array('id' => 'PE', 'name' => 'Peru'), array('id' => 'PH', 'name' => 'Philippines'), array('id' => 'PN', 'name' => 'Pitcairn'), array('id' => 'PL', 'name' => 'Poland'), array('id' => 'PT', 'name' => 'Portugal'), array('id' => 'PR', 'name' => 'Puerto Rico'), array('id' => 'QA', 'name' => 'Qatar'), array('id' => 'RE', 'name' => 'Reunion'), array('id' => 'RO', 'name' => 'Romania'), array('id' => 'RU', 'name' => 'Russian Federation'), array('id' => 'RW', 'name' => 'Rwanda'), array('id' => 'BL', 'name' => 'Saint Barthelemy'), array('id' => 'SH', 'name' => 'Saint Helena'), array('id' => 'KN', 'name' => 'Saint Kitts And Nevis'), array('id' => 'LC', 'name' => 'Saint Lucia'), array('id' => 'MF', 'name' => 'Saint Martin'), array('id' => 'PM', 'name' => 'Saint Pierre And Miquelon'), array('id' => 'VC', 'name' => 'Saint Vincent And Grenadines'), array('id' => 'WS', 'name' => 'Samoa'), array('id' => 'SM', 'name' => 'San Marino'), array('id' => 'ST', 'name' => 'Sao Tome And Principe'), array('id' => 'SA', 'name' => 'Saudi Arabia'), array('id' => 'SN', 'name' => 'Senegal'), array('id' => 'RS', 'name' => 'Serbia'), array('id' => 'SC', 'name' => 'Seychelles'), array('id' => 'SL', 'name' => 'Sierra Leone'), array('id' => 'SG', 'name' => 'Singapore'), array('id' => 'SK', 'name' => 'Slovakia'), array('id' => 'SI', 'name' => 'Slovenia'), array('id' => 'SB', 'name' => 'Solomon Islands'), array('id' => 'SO', 'name' => 'Somalia'), array('id' => 'ZA', 'name' => 'South Africa'), array('id' => 'GS', 'name' => 'South Georgia And Sandwich Isl.'), array('id' => 'ES', 'name' => 'Spain'), array('id' => 'LK', 'name' => 'Sri Lanka'), array('id' => 'SD', 'name' => 'Sudan'), array('id' => 'SR', 'name' => 'Suriname'), array('id' => 'SJ', 'name' => 'Svalbard And Jan Mayen'), array('id' => 'SZ', 'name' => 'Swaziland'), array('id' => 'SE', 'name' => 'Sweden'), array('id' => 'CH', 'name' => 'Switzerland'), array('id' => 'SY', 'name' => 'Syrian Arab Republic'), array('id' => 'TW', 'name' => 'Taiwan'), array('id' => 'TJ', 'name' => 'Tajikistan'), array('id' => 'TZ', 'name' => 'Tanzania'), array('id' => 'TH', 'name' => 'Thailand'), array('id' => 'TL', 'name' => 'Timor-Leste'), array('id' => 'TG', 'name' => 'Togo'), array('id' => 'TK', 'name' => 'Tokelau'), array('id' => 'TO', 'name' => 'Tonga'), array('id' => 'TT', 'name' => 'Trinidad And Tobago'), array('id' => 'TN', 'name' => 'Tunisia'), array('id' => 'TR', 'name' => 'Turkey'), array('id' => 'TM', 'name' => 'Turkmenistan'), array('id' => 'TC', 'name' => 'Turks And Caicos Islands'), array('id' => 'TV', 'name' => 'Tuvalu'), array('id' => 'UG', 'name' => 'Uganda'), array('id' => 'UA', 'name' => 'Ukraine'), array('id' => 'AE', 'name' => 'United Arab Emirates'), array('id' => 'GB', 'name' => 'United Kingdom'), array('id' => 'US', 'name' => 'United States'), array('id' => 'UM', 'name' => 'United States Outlying Islands'), array('id' => 'UY', 'name' => 'Uruguay'), array('id' => 'UZ', 'name' => 'Uzbekistan'), array('id' => 'VU', 'name' => 'Vanuatu'), array('id' => 'VE', 'name' => 'Venezuela'), array('id' => 'VN', 'name' => 'Viet Nam'), array('id' => 'VG', 'name' => 'Virgin Islands, British'), array('id' => 'VI', 'name' => 'Virgin Islands, U.S.'), array('id' => 'WF', 'name' => 'Wallis And Futuna'), array('id' => 'EH', 'name' => 'Western Sahara'), array('id' => 'YE', 'name' => 'Yemen'), array('id' => 'ZM', 'name' => 'Zambia'), array('id' => 'ZW', 'name' => 'Zimbabwe')); + + /** GeoIP filter code => country name ("All Countries" + special buckets first). */ + private const GEO_COUNTRIES = array('ALL' => 'All Countries', 'A1' => 'Anonymous Proxy', 'A2' => 'Satellite Provider', 'O1' => 'Other Country', 'AF' => 'Afghanistan', 'AX' => 'Aland Islands', 'AL' => 'Albania', 'DZ' => 'Algeria', 'AS' => 'American Samoa', 'AD' => 'Andorra', 'AO' => 'Angola', 'AI' => 'Anguilla', 'AQ' => 'Antarctica', 'AG' => 'Antigua And Barbuda', 'AR' => 'Argentina', 'AM' => 'Armenia', 'AW' => 'Aruba', 'AU' => 'Australia', 'AT' => 'Austria', 'AZ' => 'Azerbaijan', 'BS' => 'Bahamas', 'BH' => 'Bahrain', 'BD' => 'Bangladesh', 'BB' => 'Barbados', 'BY' => 'Belarus', 'BE' => 'Belgium', 'BZ' => 'Belize', 'BJ' => 'Benin', 'BM' => 'Bermuda', 'BT' => 'Bhutan', 'BO' => 'Bolivia', 'BA' => 'Bosnia And Herzegovina', 'BW' => 'Botswana', 'BV' => 'Bouvet Island', 'BR' => 'Brazil', 'IO' => 'British Indian Ocean Territory', 'BN' => 'Brunei Darussalam', 'BG' => 'Bulgaria', 'BF' => 'Burkina Faso', 'BI' => 'Burundi', 'KH' => 'Cambodia', 'CM' => 'Cameroon', 'CA' => 'Canada', 'CV' => 'Cape Verde', 'KY' => 'Cayman Islands', 'CF' => 'Central African Republic', 'TD' => 'Chad', 'CL' => 'Chile', 'CN' => 'China', 'CX' => 'Christmas Island', 'CC' => 'Cocos (Keeling) Islands', 'CO' => 'Colombia', 'KM' => 'Comoros', 'CG' => 'Congo', 'CD' => 'Congo, Democratic Republic', 'CK' => 'Cook Islands', 'CR' => 'Costa Rica', 'CI' => "Cote D'Ivoire", 'HR' => 'Croatia', 'CU' => 'Cuba', 'CY' => 'Cyprus', 'CZ' => 'Czech Republic', 'DK' => 'Denmark', 'DJ' => 'Djibouti', 'DM' => 'Dominica', 'DO' => 'Dominican Republic', 'EC' => 'Ecuador', 'EG' => 'Egypt', 'SV' => 'El Salvador', 'GQ' => 'Equatorial Guinea', 'ER' => 'Eritrea', 'EE' => 'Estonia', 'ET' => 'Ethiopia', 'FK' => 'Falkland Islands (Malvinas)', 'FO' => 'Faroe Islands', 'FJ' => 'Fiji', 'FI' => 'Finland', 'FR' => 'France', 'GF' => 'French Guiana', 'PF' => 'French Polynesia', 'TF' => 'French Southern Territories', 'MK' => 'Fyrom', 'GA' => 'Gabon', 'GM' => 'Gambia', 'GE' => 'Georgia', 'DE' => 'Germany', 'GH' => 'Ghana', 'GI' => 'Gibraltar', 'GR' => 'Greece', 'GL' => 'Greenland', 'GD' => 'Grenada', 'GP' => 'Guadeloupe', 'GU' => 'Guam', 'GT' => 'Guatemala', 'GG' => 'Guernsey', 'GN' => 'Guinea', 'GW' => 'Guinea-Bissau', 'GY' => 'Guyana', 'HT' => 'Haiti', 'HM' => 'Heard Island & Mcdonald Islands', 'VA' => 'Holy See (Vatican City State)', 'HN' => 'Honduras', 'HK' => 'Hong Kong', 'HU' => 'Hungary', 'IS' => 'Iceland', 'IN' => 'India', 'ID' => 'Indonesia', 'IR' => 'Iran, Islamic Republic Of', 'IQ' => 'Iraq', 'IE' => 'Ireland', 'IM' => 'Isle Of Man', 'IL' => 'Israel', 'IT' => 'Italy', 'JM' => 'Jamaica', 'JP' => 'Japan', 'JE' => 'Jersey', 'JO' => 'Jordan', 'KZ' => 'Kazakhstan', 'KE' => 'Kenya', 'KI' => 'Kiribati', 'KR' => 'Korea', 'KW' => 'Kuwait', 'KG' => 'Kyrgyzstan', 'LA' => "Lao People's Democratic Republic", 'LV' => 'Latvia', 'LB' => 'Lebanon', 'LS' => 'Lesotho', 'LR' => 'Liberia', 'LY' => 'Libyan Arab Jamahiriya', 'LI' => 'Liechtenstein', 'LT' => 'Lithuania', 'LU' => 'Luxembourg', 'MO' => 'Macao', 'MG' => 'Madagascar', 'MW' => 'Malawi', 'MY' => 'Malaysia', 'MV' => 'Maldives', 'ML' => 'Mali', 'MT' => 'Malta', 'MH' => 'Marshall Islands', 'MQ' => 'Martinique', 'MR' => 'Mauritania', 'MU' => 'Mauritius', 'YT' => 'Mayotte', 'MX' => 'Mexico', 'FM' => 'Micronesia, Federated States Of', 'MD' => 'Moldova', 'MC' => 'Monaco', 'MN' => 'Mongolia', 'ME' => 'Montenegro', 'MS' => 'Montserrat', 'MA' => 'Morocco', 'MZ' => 'Mozambique', 'MM' => 'Myanmar', 'NA' => 'Namibia', 'NR' => 'Nauru', 'NP' => 'Nepal', 'NL' => 'Netherlands', 'AN' => 'Netherlands Antilles', 'NC' => 'New Caledonia', 'NZ' => 'New Zealand', 'NI' => 'Nicaragua', 'NE' => 'Niger', 'NG' => 'Nigeria', 'NU' => 'Niue', 'NF' => 'Norfolk Island', 'MP' => 'Northern Mariana Islands', 'NO' => 'Norway', 'OM' => 'Oman', 'PK' => 'Pakistan', 'PW' => 'Palau', 'PS' => 'Palestinian Territory, Occupied', 'PA' => 'Panama', 'PG' => 'Papua New Guinea', 'PY' => 'Paraguay', 'PE' => 'Peru', 'PH' => 'Philippines', 'PN' => 'Pitcairn', 'PL' => 'Poland', 'PT' => 'Portugal', 'PR' => 'Puerto Rico', 'QA' => 'Qatar', 'RE' => 'Reunion', 'RO' => 'Romania', 'RU' => 'Russian Federation', 'RW' => 'Rwanda', 'BL' => 'Saint Barthelemy', 'SH' => 'Saint Helena', 'KN' => 'Saint Kitts And Nevis', 'LC' => 'Saint Lucia', 'MF' => 'Saint Martin', 'PM' => 'Saint Pierre And Miquelon', 'VC' => 'Saint Vincent And Grenadines', 'WS' => 'Samoa', 'SM' => 'San Marino', 'ST' => 'Sao Tome And Principe', 'SA' => 'Saudi Arabia', 'SN' => 'Senegal', 'RS' => 'Serbia', 'SC' => 'Seychelles', 'SL' => 'Sierra Leone', 'SG' => 'Singapore', 'SK' => 'Slovakia', 'SI' => 'Slovenia', 'SB' => 'Solomon Islands', 'SO' => 'Somalia', 'ZA' => 'South Africa', 'GS' => 'South Georgia And Sandwich Isl.', 'ES' => 'Spain', 'LK' => 'Sri Lanka', 'SD' => 'Sudan', 'SR' => 'Suriname', 'SJ' => 'Svalbard And Jan Mayen', 'SZ' => 'Swaziland', 'SE' => 'Sweden', 'CH' => 'Switzerland', 'SY' => 'Syrian Arab Republic', 'TW' => 'Taiwan', 'TJ' => 'Tajikistan', 'TZ' => 'Tanzania', 'TH' => 'Thailand', 'TL' => 'Timor-Leste', 'TG' => 'Togo', 'TK' => 'Tokelau', 'TO' => 'Tonga', 'TT' => 'Trinidad And Tobago', 'TN' => 'Tunisia', 'TR' => 'Turkey', 'TM' => 'Turkmenistan', 'TC' => 'Turks And Caicos Islands', 'TV' => 'Tuvalu', 'UG' => 'Uganda', 'UA' => 'Ukraine', 'AE' => 'United Arab Emirates', 'GB' => 'United Kingdom', 'US' => 'United States', 'UM' => 'United States Outlying Islands', 'UY' => 'Uruguay', 'UZ' => 'Uzbekistan', 'VU' => 'Vanuatu', 'VE' => 'Venezuela', 'VN' => 'Viet Nam', 'VG' => 'Virgin Islands, British', 'VI' => 'Virgin Islands, U.S.', 'WF' => 'Wallis And Futuna', 'EH' => 'Western Sahara', 'YE' => 'Yemen', 'ZM' => 'Zambia', 'ZW' => 'Zimbabwe'); + + /** + * ISO 3166-1 alpha-2 code => official country name. + * + * @return array + */ + public static function countryCodes(): array { + return self::COUNTRY_CODES; + } + + /** + * Ordered list of `['id' => code, 'name' => label]` rows for the + * country blocking dropdown (leading "Off" + special buckets). + * + * @return array + */ + public static function countries(): array { + return self::COUNTRIES; + } + + /** + * GeoIP filter code => country name (leading "All Countries" bucket). + * + * @return array + */ + public static function geoCountries(): array { + return self::GEO_COUNTRIES; + } +} diff --git a/src/Core/Reference/LocaleReference.php b/src/Core/Reference/LocaleReference.php new file mode 100644 index 00000000..6d85ce8a --- /dev/null +++ b/src/Core/Reference/LocaleReference.php @@ -0,0 +1,32 @@ + + * @copyright 2025-2026 Vateron Media + * @link https://github.com/Vateron-Media/XC_VM + * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html + */ +final class LocaleReference { + /** ISO 639-1 language code => display name (leading "Default - EN"). */ + private const TMDB_LANGUAGES = array('' => 'Default - EN', 'aa' => 'Afar', 'af' => 'Afrikaans', 'ak' => 'Akan', 'an' => 'Aragonese', 'as' => 'Assamese', 'av' => 'Avaric', 'ae' => 'Avestan', 'ay' => 'Aymara', 'az' => 'Azerbaijani', 'ba' => 'Bashkir', 'bm' => 'Bambara', 'bi' => 'Bislama', 'bo' => 'Tibetan', 'br' => 'Breton', 'ca' => 'Catalan', 'cs' => 'Czech', 'ce' => 'Chechen', 'cu' => 'Slavic', 'cv' => 'Chuvash', 'kw' => 'Cornish', 'co' => 'Corsican', 'cr' => 'Cree', 'cy' => 'Welsh', 'da' => 'Danish', 'de' => 'German', 'dv' => 'Divehi', 'dz' => 'Dzongkha', 'eo' => 'Esperanto', 'et' => 'Estonian', 'eu' => 'Basque', 'fo' => 'Faroese', 'fj' => 'Fijian', 'fi' => 'Finnish', 'fr' => 'French', 'fy' => 'Frisian', 'ff' => 'Fulah', 'gd' => 'Gaelic', 'ga' => 'Irish', 'gl' => 'Galician', 'gv' => 'Manx', 'gn' => 'Guarani', 'gu' => 'Gujarati', 'ht' => 'Haitian', 'ha' => 'Hausa', 'sh' => 'Serbo-Croatian', 'hz' => 'Herero', 'ho' => 'Hiri Motu', 'hr' => 'Croatian', 'hu' => 'Hungarian', 'ig' => 'Igbo', 'io' => 'Ido', 'ii' => 'Yi', 'iu' => 'Inuktitut', 'ie' => 'Interlingue', 'ia' => 'Interlingua', 'id' => 'Indonesian', 'ik' => 'Inupiaq', 'is' => 'Icelandic', 'it' => 'Italian', 'ja' => 'Japanese', 'kl' => 'Kalaallisut', 'kn' => 'Kannada', 'ks' => 'Kashmiri', 'kr' => 'Kanuri', 'kk' => 'Kazakh', 'km' => 'Khmer', 'ki' => 'Kikuyu', 'rw' => 'Kinyarwanda', 'ky' => 'Kirghiz', 'kv' => 'Komi', 'kg' => 'Kongo', 'ko' => 'Korean', 'kj' => 'Kuanyama', 'ku' => 'Kurdish', 'lo' => 'Lao', 'la' => 'Latin', 'lv' => 'Latvian', 'li' => 'Limburgish', 'ln' => 'Lingala', 'lt' => 'Lithuanian', 'lb' => 'Letzeburgesch', 'lu' => 'Luba-Katanga', 'lg' => 'Ganda', 'mh' => 'Marshall', 'ml' => 'Malayalam', 'mr' => 'Marathi', 'mg' => 'Malagasy', 'mt' => 'Maltese', 'mo' => 'Moldavian', 'mn' => 'Mongolian', 'mi' => 'Maori', 'ms' => 'Malay', 'my' => 'Burmese', 'na' => 'Nauru', 'nv' => 'Navajo', 'nr' => 'Ndebele', 'nd' => 'Ndebele', 'ng' => 'Ndonga', 'ne' => 'Nepali', 'nl' => 'Dutch', 'nn' => 'Norwegian Nynorsk', 'nb' => 'Norwegian Bokmal', 'no' => 'Norwegian', 'ny' => 'Chichewa', 'oc' => 'Occitan', 'oj' => 'Ojibwa', 'or' => 'Oriya', 'om' => 'Oromo', 'os' => 'Ossetian; Ossetic', 'pi' => 'Pali', 'pl' => 'Polish', 'pt' => 'Portuguese', 'pt-BR' => 'Portuguese - Brazil', 'qu' => 'Quechua', 'rm' => 'Raeto-Romance', 'ro' => 'Romanian', 'rn' => 'Rundi', 'ru' => 'Russian', 'sg' => 'Sango', 'sa' => 'Sanskrit', 'si' => 'Sinhalese', 'sk' => 'Slovak', 'sl' => 'Slovenian', 'se' => 'Northern Sami', 'sm' => 'Samoan', 'sn' => 'Shona', 'sd' => 'Sindhi', 'so' => 'Somali', 'st' => 'Sotho', 'es' => 'Spanish', 'sq' => 'Albanian', 'sc' => 'Sardinian', 'sr' => 'Serbian', 'ss' => 'Swati', 'su' => 'Sundanese', 'sw' => 'Swahili', 'sv' => 'Swedish', 'ty' => 'Tahitian', 'ta' => 'Tamil', 'tt' => 'Tatar', 'te' => 'Telugu', 'tg' => 'Tajik', 'tl' => 'Tagalog', 'th' => 'Thai', 'ti' => 'Tigrinya', 'to' => 'Tonga', 'tn' => 'Tswana', 'ts' => 'Tsonga', 'tk' => 'Turkmen', 'tr' => 'Turkish', 'tw' => 'Twi', 'ug' => 'Uighur', 'uk' => 'Ukrainian', 'ur' => 'Urdu', 'uz' => 'Uzbek', 've' => 'Venda', 'vi' => 'Vietnamese', 'vo' => 'Volapük', 'wa' => 'Walloon', 'wo' => 'Wolof', 'xh' => 'Xhosa', 'yi' => 'Yiddish', 'za' => 'Zhuang', 'zu' => 'Zulu', 'ab' => 'Abkhazian', 'zh' => 'Mandarin', 'ps' => 'Pushto', 'am' => 'Amharic', 'ar' => 'Arabic', 'bg' => 'Bulgarian', 'cn' => 'Cantonese', 'mk' => 'Macedonian', 'el' => 'Greek', 'fa' => 'Persian', 'he' => 'Hebrew', 'hi' => 'Hindi', 'hy' => 'Armenian', 'en' => 'English', 'ee' => 'Ewe', 'ka' => 'Georgian', 'pa' => 'Punjabi', 'bn' => 'Bengali', 'bs' => 'Bosnian', 'ch' => 'Chamorro', 'be' => 'Belarusian', 'yo' => 'Yoruba'); + + /** + * ISO 639-1 language code => display name for TMDb metadata language + * selectors (leading empty key = "Default - EN"). + * + * @return array + */ + public static function tmdbLanguages(): array { + return self::TMDB_LANGUAGES; + } +} diff --git a/src/Core/Reference/PermissionReference.php b/src/Core/Reference/PermissionReference.php new file mode 100644 index 00000000..ca2d0978 --- /dev/null +++ b/src/Core/Reference/PermissionReference.php @@ -0,0 +1,162 @@ + + * @copyright 2025-2026 Vateron Media + * @link https://github.com/Vateron-Media/XC_VM + * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html + */ +final class PermissionReference { + /** Ordered list of reseller sub-permission keys. */ + private const KEYS = array( + 'add_rtmp', + 'add_bouquet', + 'add_cat', + 'add_e2', + 'add_epg', + 'add_episode', + 'add_group', + 'add_mag', + 'add_movie', + 'add_packages', + 'add_radio', + 'add_reguser', + 'add_server', + 'add_stream', + 'tprofile', + 'add_series', + 'add_user', + 'block_ips', + 'block_isps', + 'block_uas', + 'create_channel', + 'edit_bouquet', + 'edit_cat', + 'channel_order', + 'edit_cchannel', + 'edit_e2', + 'epg_edit', + 'edit_episode', + 'folder_watch_settings', + 'settings', + 'edit_group', + 'edit_mag', + 'edit_movie', + 'edit_package', + 'edit_radio', + 'edit_reguser', + 'edit_server', + 'edit_stream', + 'edit_series', + 'edit_user', + 'fingerprint', + 'import_episodes', + 'import_movies', + 'import_streams', + 'database', + 'mass_delete', + 'mass_sedits_vod', + 'mass_sedits', + 'mass_edit_users', + 'mass_edit_lines', + 'mass_edit_mags', + 'mass_edit_enigmas', + 'mass_edit_streams', + 'mass_edit_radio', + 'mass_edit_reguser', + 'ticket', + 'subreseller', + 'stream_tools', + 'bouquets', + 'categories', + 'client_request_log', + 'connection_logs', + 'manage_cchannels', + 'credits_log', + 'index', + 'manage_e2', + 'epg', + 'folder_watch', + 'folder_watch_output', + 'mng_groups', + 'live_connections', + 'login_logs', + 'manage_mag', + 'manage_events', + 'movies', + 'mng_packages', + 'player', + 'process_monitor', + 'radio', + 'mng_regusers', + 'reg_userlog', + 'rtmp', + 'servers', + 'stream_errors', + 'streams', + 'subresellers', + 'manage_tickets', + 'tprofiles', + 'series', + 'users', + 'episodes', + 'edit_tprofile', + 'folder_watch_add', + 'add_code', + 'add_hmac', + 'block_asns', + 'panel_logs', + 'quick_tools', + 'restream_logs' + ); + + /** @var array|null Memoised advanced-permission rows. */ + private static ?array $advanced = null; + + /** + * Ordered list of reseller sub-permission keys. + * + * @return array + */ + public static function keys(): array { + return self::KEYS; + } + + /** + * Localized advanced-permission rows for the group editor, each row + * being `[key, title, description]`. Built once and memoised. + * + * @return array + */ + public static function advanced(): array { + if (self::$advanced !== null) { + return self::$advanced; + } + + $rows = []; + foreach (self::KEYS as $key) { + $rows[] = array( + $key, + Translator::get('permission_' . $key), + Translator::get('permission_' . $key . '_text'), + ); + } + + self::$advanced = $rows; + return $rows; + } +} diff --git a/src/Core/Reference/StatusBadge.php b/src/Core/Reference/StatusBadge.php new file mode 100644 index 00000000..fc037c96 --- /dev/null +++ b/src/Core/Reference/StatusBadge.php @@ -0,0 +1,86 @@ + + * @copyright 2025-2026 Vateron Media + * @link https://github.com/Vateron-Media/XC_VM + * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html + */ +final class StatusBadge { + /** Live stream status code => badge HTML. */ + private const STREAM = array(-1 => "", 0 => "", 1 => "", 2 => "", 3 => "", 4 => "", 5 => "", 6 => "", 7 => ""); + + /** Live-search animated status code => badge HTML (legacy positional keys preserved). */ + private const SEARCH = array(-1 => "", 0 => "", "", "", "", "", 7 => "", 8 => "", 9 => "", 10 => ""); + + /** VOD encode status code => badge HTML. */ + private const VOD = array(-1 => "", 0 => "", 1 => "", 2 => "", 3 => "", 4 => "", 5 => ""); + + /** VOD folder-watch import status code => badge HTML. */ + private const WATCH = array(1 => "", 2 => "", 3 => "", 4 => "", 5 => "", 6 => ""); + + /** Stream failure/log action => badge HTML. */ + private const FAILURE = array('STREAM_STOP' => "", 'STREAM_START_FAIL' => "", 'STREAM_START' => "", 'STREAM_RESTART' => "", 'STREAM_FAILED' => ""); + + /** Stream-log action => human-readable label. */ + private const STREAM_LOG = array('STREAM_FAILED' => 'Stream Failed', 'STREAM_START' => 'Stream Started', 'STREAM_RESTART' => 'Stream Restarted', 'STREAM_STOP' => 'Stream Stopped', 'FORCE_SOURCE' => 'Force Change Source', 'AUTO_RESTART' => 'Timed Auto Restart', 'AUDIO_LOSS' => 'Audio Lost', 'PRIORITY_SWITCH' => 'Priority Switch', 'DELAY_START' => 'Delay Started', 'FFMPEG_ERROR' => 'FFMPEG Error'); + + /** + * Live stream status badge. Unknown codes fall back to the STOPPED + * badge, matching the legacy `$rStatusArray[$x] ?? $rStatusArray[0]`. + */ + public static function stream(int $status): string { + return self::STREAM[$status] ?? self::STREAM[0]; + } + + /** + * Live-search animated status badge ('' for unknown codes). + */ + public static function search(int $status): string { + return self::SEARCH[$status] ?? ''; + } + + /** + * VOD encode status badge ('' for unknown codes). + */ + public static function vod(int $status): string { + return self::VOD[$status] ?? ''; + } + + /** + * VOD folder-watch import status badge ('' for unknown codes). + */ + public static function watch(int $status): string { + return self::WATCH[$status] ?? ''; + } + + /** + * Stream failure/log action badge ('' for unknown actions). + */ + public static function failure(string $action): string { + return self::FAILURE[$action] ?? ''; + } + + /** + * Stream-log action label ('' for unknown actions). + */ + public static function streamLog(string $action): string { + return self::STREAM_LOG[$action] ?? ''; + } +} diff --git a/src/Core/Reference/UiReference.php b/src/Core/Reference/UiReference.php new file mode 100644 index 00000000..6ca9fdc9 --- /dev/null +++ b/src/Core/Reference/UiReference.php @@ -0,0 +1,32 @@ + + * @copyright 2025-2026 Vateron Media + * @link https://github.com/Vateron-Media/XC_VM + * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html + */ +final class UiReference { + /** CSS accent class => human-readable colour name (leading "" = Default). */ + private const HUES = array('' => 'Default', 'primary' => 'Blue', 'info' => 'Light Blue', 'success' => 'Green', 'danger' => 'Red', 'warning' => 'Orange', 'purple' => 'Purple', 'pink' => 'Pink', 'dark' => 'Dark Grey', 'secondary' => 'Light Grey'); + + /** + * CSS accent class => human-readable colour name for the profile + * hue selector (leading empty key = "Default"). + * + * @return array + */ + public static function hues(): array { + return self::HUES; + } +} diff --git a/src/Domain/User/ResellerAPI.php b/src/Domain/User/ResellerAPI.php index ac8b6582..2022cd66 100644 --- a/src/Domain/User/ResellerAPI.php +++ b/src/Domain/User/ResellerAPI.php @@ -7,6 +7,7 @@ use XcVm\Core\Auth\Authorization; use XcVm\Core\Auth\AuthRepository; use XcVm\Core\Config\SettingsManager; use XcVm\Core\Database\QueryHelper; +use XcVm\Core\Reference\UiReference; use XcVm\Core\Util\AdminHelpers; use XcVm\Domain\Bouquet\BouquetService; use XcVm\Domain\Device\EnigmaService; @@ -86,7 +87,6 @@ class ResellerAPI { */ public static function editResellerProfile($rData) { $db = self::db(); - global $rHues; global $allowedLangs; $rData = self::processData('profile', $rData); @@ -108,7 +108,7 @@ class ResellerAPI { $rData['api_key'] = ''; } - if (!in_array($rData['hue'], $rHues)) { + if (!in_array($rData['hue'], UiReference::hues())) { $rData['hue'] = ''; } diff --git a/src/Public/Controllers/Admin/Ajax/SearchAjaxController.php b/src/Public/Controllers/Admin/Ajax/SearchAjaxController.php index 5c161cb2..f326032f 100644 --- a/src/Public/Controllers/Admin/Ajax/SearchAjaxController.php +++ b/src/Public/Controllers/Admin/Ajax/SearchAjaxController.php @@ -5,6 +5,7 @@ namespace XcVm\Public\Controllers\Admin\Ajax; use XcVm\Core\Auth\Authorization; use XcVm\Core\Config\SettingsManager; use XcVm\Core\Http\RequestManager; +use XcVm\Core\Reference\StatusBadge; use XcVm\Core\Util\AdminHelpers; use XcVm\Core\Util\TimeUtils; use XcVm\Domain\Stream\CategoryService; @@ -18,8 +19,9 @@ use XcVm\Domain\User\GroupService; * (live/VOD/created channels/radio/episodes) and series. Each result item * carries structured `data` that the client renders into a card (see * docs/adr/search-json-contract.md); permission checks, status resolution and - * category/server lookups stay server-side. `$language` and `$rSearchStatusArray` - * are bootstrap globals it relies on, alongside `$db` / `$rServers`. + * category/server lookups stay server-side. Status badges resolve via + * {@see \XcVm\Core\Reference\StatusBadge}; `$language`, `$db` and `$rServers` + * remain bootstrap globals it relies on. * * @package XC_VM_Public_Controllers_Admin * @author Divarion_D @@ -34,7 +36,7 @@ class SearchAjaxController extends BaseAjaxController { $this->requireXhr(); /** @var class-string $language */ - global $db, $rServers, $language, $rSearchStatusArray; + global $db, $rServers, $language; $rReturn = array('total_count' => 0, 'items' => array(), 'result' => true); $rTables = array('lines' => array('Lines', 'line?id=', '`username`, `admin_notes`, `reseller_notes`, `last_ip`, `contact`', 'id', 'username'), 'mag_devices' => array('MAG Devices', 'mag?id=', '`mac_filter`, `ip`', 'mag_id', 'mac'), 'enigma2_devices' => array('Enigma2 Devices', 'enigma?id=', '`mac_filter`, `public_ip`', 'device_id', 'mac'), 'users' => array('Users', 'user?id=', '`username`, `email`, `ip`, `notes`, `reseller_dns`', 'id', 'username'), 'streams' => array('Streams, Movies & Episodes', 'stream_view?id=', '`stream_display_name`, `stream_source`, `notes`, `channel_id`', 'id', 'stream_display_name'), 'streams_series' => array('TV Series', 'serie?id=', '`title`, `plot`, `cast`, `director`', 'id', 'title')); @@ -586,10 +588,9 @@ class SearchAjaxController extends BaseAjaxController { return array('kind' => 'status') + $this->statusMeta($rCode); } - /** Derive {code, label, variant} for a status code from $rSearchStatusArray. */ + /** Derive {code, label, variant} for a status code from StatusBadge::search(). */ private function statusMeta(int $rCode): array { - global $rSearchStatusArray; - $rHtml = $rSearchStatusArray[$rCode] ?? ''; + $rHtml = StatusBadge::search($rCode); preg_match('/bg-animate-(\w+)/', $rHtml, $rVariant); preg_match('/>([^<]+)isDark()) { $rColours = array(1 => array('secondary', '#7e8e9d', '#ffffff'), 2 => array('secondary', '#7e8e9d', '#ffffff'), 3 => array('secondary', '#7e8e9d', '#ffffff'), 4 => array('secondary', '#7e8e9d', '#ffffff')); $rColourMap = array(array('#7e8e9d', 'bg-map-dark-1'), array('#6c7b8a', 'bg-map-dark-2'), array('#5a6977', 'bg-map-dark-3'), array('#485765', 'bg-map-dark-4'), array('#374654', 'bg-map-dark-5'), array('#273643', 'bg-map-dark-6')); } else { diff --git a/src/Public/Controllers/Admin/SettingsController.php b/src/Public/Controllers/Admin/SettingsController.php index 366cff80..5aed8c47 100644 --- a/src/Public/Controllers/Admin/SettingsController.php +++ b/src/Public/Controllers/Admin/SettingsController.php @@ -40,11 +40,6 @@ class SettingsController extends BaseAdminController { $BinVersion = $binVersionData['release'] ?? 'N/A'; $BinOS = self::resolveOsLabel($binVersionData); - // Global lookup arrays from includes/admin.php needed by settings view - $rTMDBLanguages = $GLOBALS['rTMDBLanguages'] ?? []; - $rGeoCountries = $GLOBALS['rGeoCountries'] ?? []; - $rMAGs = $GLOBALS['rMAGs'] ?? []; - $this->setTitle('Settings'); $this->render('settings', compact( 'rSettings', @@ -54,10 +49,7 @@ class SettingsController extends BaseAdminController { 'Nginx', 'BinVersion', 'BinOS', - 'rUpdate', - 'rTMDBLanguages', - 'rGeoCountries', - 'rMAGs' + 'rUpdate' )); } diff --git a/src/Public/Controllers/Admin/TableController.php b/src/Public/Controllers/Admin/TableController.php index 07c402c4..4ce1d450 100644 --- a/src/Public/Controllers/Admin/TableController.php +++ b/src/Public/Controllers/Admin/TableController.php @@ -6,7 +6,9 @@ use XcVm\Core\Auth\Authorization; use XcVm\Core\Auth\AuthRepository; use XcVm\Core\Backup\BackupService; use XcVm\Core\Config\SettingsManager; +use XcVm\Core\Enum\ClientFilter; use XcVm\Core\Http\RequestManager; +use XcVm\Core\Reference\StatusBadge; use XcVm\Core\Util\TimeUtils; use XcVm\Domain\Device\EnigmaService; use XcVm\Domain\Device\MagService; @@ -1062,8 +1064,7 @@ class TableController extends BaseAdminController { } private function handleStreams($rReturn, $rStart, $rLimit, $rIsAPI) { - global $db, $rSettings, $rServers, $language, - $rStatusArray; + global $db, $rSettings, $rServers, $language; if (!Authorization::check("adv", "streams") && !Authorization::check("adv", "mass_edit_streams")) { exit; } @@ -1423,7 +1424,7 @@ class TableController extends BaseAdminController { $rPercent = (int) $rPercent; $rUptime = ""; } else { - $rUptime = $rStatusArray[$rActualStatus]; + $rUptime = StatusBadge::stream($rActualStatus); } if (in_array($rActualStatus, [1, 2, 3])) { if ($rCreated) { @@ -1654,8 +1655,7 @@ class TableController extends BaseAdminController { } private function handleRadios($rReturn, $rStart, $rLimit, $rIsAPI) { - global $db, $rSettings, $rServers, $language, - $rStatusArray; + global $db, $rSettings, $rServers, $language; if (!Authorization::check("adv", "radio") && !Authorization::check("adv", "mass_edit_radio")) { exit; } @@ -1865,7 +1865,7 @@ class TableController extends BaseAdminController { } elseif ($rActualStatus == 3) { $rUptime = ""; } else { - $rUptime = $rStatusArray[$rActualStatus]; + $rUptime = StatusBadge::stream($rActualStatus); } $rUptime = str_replace("btn-fixed'", "btn-fixed-xl'", $rUptime); if (SettingsManager::getAll()["group_buttons"]) { @@ -1967,7 +1967,7 @@ class TableController extends BaseAdminController { } private function handleMovies($rReturn, $rStart, $rLimit, $rIsAPI) { - global $db, $rSettings, $rServers, $rVODStatusArray; + global $db, $rSettings, $rServers; if (!Authorization::check("adv", "movies") && !Authorization::check("adv", "mass_sedits_vod")) { exit; } @@ -2330,7 +2330,7 @@ class TableController extends BaseAdminController { if (!$rSettings["streams_grouped"] && 1 < $rServerCount[$rRow["id"]]) { $rID .= "-" . $rRow["server_id"]; } - $rReturn["data"][] = ["" . $rID . "", $rImage, $rStreamName, $rServerName, $rClients, $rVODStatusArray[$rActualStatus], $rTMDB, $rButtons, $rPlayer, $rStreamInfoText]; + $rReturn["data"][] = ["" . $rID . "", $rImage, $rStreamName, $rServerName, $rClients, StatusBadge::vod($rActualStatus), $rTMDB, $rButtons, $rPlayer, $rStreamInfoText]; } } } @@ -2340,7 +2340,7 @@ class TableController extends BaseAdminController { } private function handleEpisodeList($rReturn, $rStart, $rLimit, $rIsAPI) { - global $db, $rVODStatusArray; + global $db; if (!Authorization::check("adv", "import_episodes") && !Authorization::check("adv", "mass_delete")) { exit; } @@ -2456,7 +2456,7 @@ class TableController extends BaseAdminController { if (0 < strlen($rProperties["movie_image"] ?? '') && SettingsManager::getAll()["show_images"]) { $rImage = ""; } - $rReturn["data"][] = [$rRow["id"], $rImage, $rStreamName, $rServerName, $rVODStatusArray[$rActualStatus]]; + $rReturn["data"][] = [$rRow["id"], $rImage, $rStreamName, $rServerName, StatusBadge::vod($rActualStatus)]; } } } @@ -2990,7 +2990,7 @@ class TableController extends BaseAdminController { } private function handleStreamList($rReturn, $rStart, $rLimit, $rIsAPI) { - global $db, $rSettings, $rStatusArray; + global $db, $rSettings; if (!Authorization::check("adv", "import_streams") && !Authorization::check("adv", "mass_delete")) { exit; } @@ -3165,7 +3165,7 @@ class TableController extends BaseAdminController { } else { $rIcon = ""; } - $rStatusText = $rStatusArray[$rActualStatus] ?? ($rStatusArray[0] ?? 'Offline'); + $rStatusText = StatusBadge::stream($rActualStatus); $rReturn["data"][] = [$rRow["id"], $rIcon, $rStreamName, $rCategory, $rServerName, $rStatusText]; } } @@ -3176,7 +3176,7 @@ class TableController extends BaseAdminController { } private function handleMovieList($rReturn, $rStart, $rLimit, $rIsAPI) { - global $db, $rVODStatusArray; + global $db; if (!Authorization::check("adv", "import_movies") && !Authorization::check("adv", "mass_delete")) { exit; } @@ -3336,7 +3336,7 @@ class TableController extends BaseAdminController { } else { $rTMDB = ""; } - $rReturn["data"][] = [$rRow["id"], $rImage, $rStreamName, $rCategory, $rServerName, $rVODStatusArray[$rActualStatus], $rTMDB]; + $rReturn["data"][] = [$rRow["id"], $rImage, $rStreamName, $rCategory, $rServerName, StatusBadge::vod($rActualStatus), $rTMDB]; } } } @@ -3346,7 +3346,7 @@ class TableController extends BaseAdminController { } private function handleRadioList($rReturn, $rStart, $rLimit, $rIsAPI) { - global $db, $rStatusArray; + global $db; if (!Authorization::check("adv", "mass_delete")) { exit; } @@ -3478,7 +3478,7 @@ class TableController extends BaseAdminController { } else { $rIcon = ""; } - $rReturn["data"][] = [$rRow["id"], $rIcon, $rRow["stream_display_name"], $rCategory, $rServerName, $rStatusArray[$rActualStatus]]; + $rReturn["data"][] = [$rRow["id"], $rIcon, $rRow["stream_display_name"], $rCategory, $rServerName, StatusBadge::stream($rActualStatus)]; } } } @@ -3744,7 +3744,6 @@ class TableController extends BaseAdminController { $rQuery = "SELECT `lines_logs`.`id`, `lines_logs`.`user_id`, `lines_logs`.`stream_id`, `streams`.`stream_display_name`, `streams`.`type`, `lines`.`username`, `lines_logs`.`client_status`, `lines_logs`.`query_string`, `lines_logs`.`user_agent`, `lines_logs`.`ip`, `lines_logs`.`extra_data`, FROM_UNIXTIME(`lines_logs`.`date`) AS `date` FROM `lines_logs` LEFT JOIN `streams` ON `streams`.`id` = `lines_logs`.`stream_id` LEFT JOIN `lines` ON `lines`.`id` = `lines_logs`.`user_id` " . $rWhereString . " " . $rOrderBy . " LIMIT " . $rStart . ", " . $rLimit . ";"; $db->query($rQuery, ...$rWhereV); if (0 < $db->num_rows()) { - $rClientFilters = (isset($rClientFilters) && is_array($rClientFilters) ? $rClientFilters : []); foreach ($db->get_rows() as $rRow) { if ($rIsAPI) { $rReturn["data"][] = self::filterRow($rRow, RequestManager::get("show_columns") ?? '', RequestManager::get("hide_columns") ?? ''); @@ -3769,7 +3768,7 @@ class TableController extends BaseAdminController { } $rExplode = explode(":", $rRow["ip"]); $rIP = "" . (1 < count($rExplode) ? implode(":", array_slice($rExplode, 0, 4)) . ":
" . implode(":", array_slice($rExplode, 4, 8)) : $rRow["ip"]) . "
"; - $rClientStatus = ($rClientFilters[$rRow["client_status"]] ?? $rRow["client_status"] ?? ""); + $rClientStatus = ClientFilter::labelFor((string) ($rRow["client_status"] ?? "")); $rExtraData = trim(strval($rRow["extra_data"] ?? "")); if ($rExtraData !== "") { $rClientStatus .= " "; @@ -4530,8 +4529,7 @@ class TableController extends BaseAdminController { } private function handleEpisodes($rReturn, $rStart, $rLimit, $rIsAPI) { - global $db, $rSettings, $rServers, - $rVODStatusArray; + global $db, $rSettings, $rServers; if (!Authorization::check("adv", "episodes") && !Authorization::check("adv", "mass_sedits")) { exit; } @@ -4867,7 +4865,7 @@ class TableController extends BaseAdminController { $rDurationText = sprintf("%02d:%02d:%02d", intdiv($rDurationSecs, 3600), intdiv($rDurationSecs % 3600, 60), $rDurationSecs % 60); } $rDurationCell = "
" . ($rDurationText ?? "--:--:--") . "
" . $rModded . "
"; - $rReturn["data"][] = ["" . $rID . "", $rImage, "" . $rStreamName . "", $rServerName, $rClients, $rVODStatusArray[$rActualStatus], $rButtons, $rPlayer, $rDurationCell, $rStreamInfoText]; + $rReturn["data"][] = ["" . $rID . "", $rImage, "" . $rStreamName . "", $rServerName, $rClients, StatusBadge::vod($rActualStatus), $rButtons, $rPlayer, $rDurationCell, $rStreamInfoText]; } } } @@ -4921,7 +4919,7 @@ class TableController extends BaseAdminController { } private function handleWatchOutput($rReturn, $rStart, $rLimit, $rIsAPI) { - global $db, $rWatchStatusArray; + global $db; if (!Authorization::check("adv", "folder_watch_output")) { exit; } @@ -4993,7 +4991,7 @@ class TableController extends BaseAdminController { } else { $rServer = $rRow["server_name"]; } - $rReturn["data"][] = [$rRow["id"], ["1" => "Movies", "2" => "Series"][$rRow["type"]], $rServer, $rRow["filename"], $rWatchStatusArray[$rRow["status"]], $rRow["dateadded"], $rButtons]; + $rReturn["data"][] = [$rRow["id"], ["1" => "Movies", "2" => "Series"][$rRow["type"]], $rServer, $rRow["filename"], StatusBadge::watch((int) $rRow["status"]), $rRow["dateadded"], $rButtons]; } } } @@ -6123,7 +6121,7 @@ class TableController extends BaseAdminController { } private function handleFailuresModal($rReturn, $rStart, $rLimit, $rIsAPI) { - global $db, $rSettings, $rFailureStatusArray; + global $db, $rSettings; if (!Authorization::check("adv", "streams")) { exit; } @@ -6158,7 +6156,7 @@ class TableController extends BaseAdminController { if (!empty($rRow["source"])) { $rStreamSource = strtolower(parse_url($rRow["source"])["host"]); } - $rReturn["data"][] = ["" . ServerRepository::getAll()[$rRow["server_id"]]["server_name"] . "", $rStreamSource, $rFailureStatusArray[$rRow["action"]], date(SettingsManager::getAll()["datetime_format"], $rRow["date"])]; + $rReturn["data"][] = ["" . ServerRepository::getAll()[$rRow["server_id"]]["server_name"] . "", $rStreamSource, StatusBadge::failure($rRow["action"]), date(SettingsManager::getAll()["datetime_format"], $rRow["date"])]; } } } @@ -6189,7 +6187,7 @@ class TableController extends BaseAdminController { } private function handleStreamLogs($rReturn, $rStart, $rLimit, $rIsAPI) { - global $db, $rStreamLogsArray; + global $db; $rOrder = ["`date`", "`action`"]; if (RequestManager::has("order") && 0 < strlen(RequestManager::get("order")[0]["column"] ?? '')) { $rOrderRow = (int) (RequestManager::get("order")[0]["column"] ?? 0); @@ -6218,7 +6216,7 @@ class TableController extends BaseAdminController { if ($rIsAPI) { $rReturn["data"][] = self::filterRow($rRow, RequestManager::get("show_columns") ?? '', RequestManager::get("hide_columns") ?? ''); } else { - $rReturn["data"][] = [date("H:i:s", $rRow["date"]), $rStreamLogsArray[$rRow["action"]]]; + $rReturn["data"][] = [date("H:i:s", $rRow["date"]), StatusBadge::streamLog($rRow["action"])]; } } } diff --git a/src/Public/Controllers/Reseller/ResellerLoginController.php b/src/Public/Controllers/Reseller/ResellerLoginController.php index 57b33635..d48a9a4a 100644 --- a/src/Public/Controllers/Reseller/ResellerLoginController.php +++ b/src/Public/Controllers/Reseller/ResellerLoginController.php @@ -22,10 +22,8 @@ use XcVm\Domain\User\ResellerAPI; * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html */ -class ResellerLoginController -{ - public function index() - { +class ResellerLoginController { + public function index() { // Bootstrap (login page is in noBootstrapPages, so FC skips bootstrap) require_once MAIN_HOME . 'bootstrap.php'; \XC_Bootstrap::boot(\XC_Bootstrap::CONTEXT_ADMIN); @@ -40,7 +38,7 @@ class ResellerLoginController // Flood protection $rSettings = SettingsManager::getAll(); - global $db, $language, $rHues; + global $db, $language; if (intval($rSettings['login_flood']) > 0) { $db->query( diff --git a/src/Public/Views/admin/client_logs.php b/src/Public/Views/admin/client_logs.php index 967f6ba7..e46dcb13 100644 --- a/src/Public/Views/admin/client_logs.php +++ b/src/Public/Views/admin/client_logs.php @@ -1,5 +1,6 @@