prismcast 1.4.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +18 -1
- package/dist/app.js.map +1 -1
- package/dist/browser/cdp.d.ts +2 -1
- package/dist/browser/cdp.js +44 -23
- package/dist/browser/cdp.js.map +1 -1
- package/dist/browser/channelSelection.d.ts +45 -1
- package/dist/browser/channelSelection.js +164 -27
- package/dist/browser/channelSelection.js.map +1 -1
- package/dist/browser/display.d.ts +0 -4
- package/dist/browser/display.js +0 -7
- package/dist/browser/display.js.map +1 -1
- package/dist/browser/index.d.ts +5 -0
- package/dist/browser/index.js +14 -0
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/precaching.d.ts +5 -0
- package/dist/browser/precaching.js +112 -0
- package/dist/browser/precaching.js.map +1 -0
- package/dist/browser/tuning/directv.d.ts +2 -0
- package/dist/browser/tuning/directv.js +723 -0
- package/dist/browser/tuning/directv.js.map +1 -0
- package/dist/browser/tuning/fox.d.ts +2 -2
- package/dist/browser/tuning/fox.js +141 -22
- package/dist/browser/tuning/fox.js.map +1 -1
- package/dist/browser/tuning/hbo.d.ts +2 -2
- package/dist/browser/tuning/hbo.js +110 -41
- package/dist/browser/tuning/hbo.js.map +1 -1
- package/dist/browser/tuning/hulu.d.ts +2 -2
- package/dist/browser/tuning/hulu.js +442 -168
- package/dist/browser/tuning/hulu.js.map +1 -1
- package/dist/browser/tuning/sling.d.ts +2 -2
- package/dist/browser/tuning/sling.js +200 -56
- package/dist/browser/tuning/sling.js.map +1 -1
- package/dist/browser/tuning/youtubeTv.d.ts +2 -2
- package/dist/browser/tuning/youtubeTv.js +243 -57
- package/dist/browser/tuning/youtubeTv.js.map +1 -1
- package/dist/browser/video.d.ts +1 -1
- package/dist/browser/video.js +4 -2
- package/dist/browser/video.js.map +1 -1
- package/dist/channels/index.js +280 -34
- package/dist/channels/index.js.map +1 -1
- package/dist/config/health.d.ts +78 -0
- package/dist/config/health.js +202 -0
- package/dist/config/health.js.map +1 -0
- package/dist/config/paths.d.ts +10 -0
- package/dist/config/paths.js +14 -0
- package/dist/config/paths.js.map +1 -1
- package/dist/config/profiles.d.ts +6 -4
- package/dist/config/profiles.js +65 -14
- package/dist/config/profiles.js.map +1 -1
- package/dist/config/providerPacks.d.ts +46 -0
- package/dist/config/providerPacks.js +200 -0
- package/dist/config/providerPacks.js.map +1 -0
- package/dist/config/providers.d.ts +36 -3
- package/dist/config/providers.js +168 -8
- package/dist/config/providers.js.map +1 -1
- package/dist/config/sites.d.ts +1 -12
- package/dist/config/sites.js +38 -5
- package/dist/config/sites.js.map +1 -1
- package/dist/config/userChannels.d.ts +12 -0
- package/dist/config/userChannels.js +81 -14
- package/dist/config/userChannels.js.map +1 -1
- package/dist/config/userConfig.d.ts +5 -1
- package/dist/config/userConfig.js +58 -6
- package/dist/config/userConfig.js.map +1 -1
- package/dist/config/userProfiles.d.ts +81 -0
- package/dist/config/userProfiles.js +424 -0
- package/dist/config/userProfiles.js.map +1 -0
- package/dist/routes/config/channels/index.d.ts +3 -0
- package/dist/routes/config/channels/index.js +3 -0
- package/dist/routes/config/channels/index.js.map +1 -0
- package/dist/routes/config/channels/routes.d.ts +6 -0
- package/dist/routes/config/channels/routes.js +797 -0
- package/dist/routes/config/channels/routes.js.map +1 -0
- package/dist/routes/config/channels/table.d.ts +46 -0
- package/dist/routes/config/channels/table.js +811 -0
- package/dist/routes/config/channels/table.js.map +1 -0
- package/dist/routes/config/index.d.ts +37 -0
- package/dist/routes/config/index.js +81 -0
- package/dist/routes/config/index.js.map +1 -0
- package/dist/routes/config/providers.d.ts +18 -0
- package/dist/routes/config/providers.js +573 -0
- package/dist/routes/config/providers.js.map +1 -0
- package/dist/routes/config/settings.d.ts +39 -0
- package/dist/routes/config/settings.js +820 -0
- package/dist/routes/config/settings.js.map +1 -0
- package/dist/routes/index.d.ts +3 -2
- package/dist/routes/index.js +7 -4
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/playlist.d.ts +5 -1
- package/dist/routes/playlist.js +32 -7
- package/dist/routes/playlist.js.map +1 -1
- package/dist/routes/providers.d.ts +6 -0
- package/dist/routes/providers.js +166 -0
- package/dist/routes/providers.js.map +1 -0
- package/dist/routes/root/content.d.ts +32 -0
- package/dist/routes/root/content.js +857 -0
- package/dist/routes/root/content.js.map +1 -0
- package/dist/routes/root/index.js +197 -0
- package/dist/routes/root/index.js.map +1 -0
- package/dist/routes/root/scripts/channels.d.ts +1 -0
- package/dist/routes/root/scripts/channels.js +745 -0
- package/dist/routes/root/scripts/channels.js.map +1 -0
- package/dist/routes/root/scripts/config.d.ts +1 -0
- package/dist/routes/root/scripts/config.js +1662 -0
- package/dist/routes/root/scripts/config.js.map +1 -0
- package/dist/routes/root/scripts/index.d.ts +3 -0
- package/dist/routes/root/scripts/index.js +8 -0
- package/dist/routes/root/scripts/index.js.map +1 -0
- package/dist/routes/root/scripts/status.d.ts +1 -0
- package/dist/routes/root/scripts/status.js +436 -0
- package/dist/routes/root/scripts/status.js.map +1 -0
- package/dist/routes/root/styles.d.ts +5 -0
- package/dist/routes/root/styles.js +447 -0
- package/dist/routes/root/styles.js.map +1 -0
- package/dist/routes/ui.js +8 -3
- package/dist/routes/ui.js.map +1 -1
- package/dist/service/commands.d.ts +5 -3
- package/dist/service/commands.js +117 -33
- package/dist/service/commands.js.map +1 -1
- package/dist/service/generators.d.ts +27 -0
- package/dist/service/generators.js +97 -6
- package/dist/service/generators.js.map +1 -1
- package/dist/streaming/hls.js +18 -1
- package/dist/streaming/hls.js.map +1 -1
- package/dist/streaming/lifecycle.js +1 -1
- package/dist/streaming/lifecycle.js.map +1 -1
- package/dist/streaming/monitor.d.ts +1 -38
- package/dist/streaming/monitor.js +2 -289
- package/dist/streaming/monitor.js.map +1 -1
- package/dist/streaming/recovery.d.ts +143 -0
- package/dist/streaming/recovery.js +286 -0
- package/dist/streaming/recovery.js.map +1 -0
- package/dist/streaming/registry.d.ts +1 -1
- package/dist/streaming/setup.d.ts +1 -1
- package/dist/streaming/setup.js +3 -1
- package/dist/streaming/setup.js.map +1 -1
- package/dist/streaming/statusEmitter.d.ts +4 -2
- package/dist/streaming/statusEmitter.js +5 -0
- package/dist/streaming/statusEmitter.js.map +1 -1
- package/dist/types/channels.d.ts +68 -0
- package/dist/types/channels.js +2 -0
- package/dist/types/channels.js.map +1 -0
- package/dist/types/config.d.ts +127 -0
- package/dist/types/config.js +2 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +7 -429
- package/dist/types/index.js +1 -5
- package/dist/types/index.js.map +1 -1
- package/dist/types/profiles.d.ts +141 -0
- package/dist/types/profiles.js +2 -0
- package/dist/types/profiles.js.map +1 -0
- package/dist/types/selection.d.ts +101 -0
- package/dist/types/selection.js +6 -0
- package/dist/types/selection.js.map +1 -0
- package/dist/types/shared.d.ts +7 -0
- package/dist/types/shared.js +6 -0
- package/dist/types/shared.js.map +1 -0
- package/dist/types/streaming.d.ts +96 -0
- package/dist/types/streaming.js +2 -0
- package/dist/types/streaming.js.map +1 -0
- package/dist/utils/debugFilter.js +3 -1
- package/dist/utils/debugFilter.js.map +1 -1
- package/dist/utils/format.d.ts +7 -0
- package/dist/utils/format.js +22 -0
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/sanitize.d.ts +14 -0
- package/dist/utils/sanitize.js +37 -0
- package/dist/utils/sanitize.js.map +1 -0
- package/package.json +5 -3
- package/dist/routes/config.d.ts +0 -76
- package/dist/routes/config.js +0 -2187
- package/dist/routes/config.js.map +0 -1
- package/dist/routes/root.js +0 -3158
- package/dist/routes/root.js.map +0 -1
- /package/dist/routes/{root.d.ts → root/index.d.ts} +0 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
/* Copyright(C) 2024-2026, HJD (https://github.com/hjdhjd). All rights reserved.
|
|
2
|
+
*
|
|
3
|
+
* userProfiles.ts: User profile and domain mapping persistence for PrismCast.
|
|
4
|
+
*/
|
|
5
|
+
import { DOMAIN_CONFIG, SITE_PROFILES } from "./sites.js";
|
|
6
|
+
import { LOG, containsNonPrintable } from "../utils/index.js";
|
|
7
|
+
import { getDataDir, getProfilesFilePath } from "./paths.js";
|
|
8
|
+
import { extractDomain } from "../utils/format.js";
|
|
9
|
+
import fs from "node:fs";
|
|
10
|
+
const { promises: fsPromises } = fs;
|
|
11
|
+
/* PrismCast allows users to define custom site profiles and domain mappings in profiles.json inside the data directory. User profiles extend built-in profiles and
|
|
12
|
+
* are merged at runtime, with user domain mappings taking precedence over built-in mappings for domain conflicts. This module handles persistence, validation, and
|
|
13
|
+
* cache management for user-defined profiles and domains.
|
|
14
|
+
*
|
|
15
|
+
* The profiles.json file contains two top-level keys:
|
|
16
|
+
* - "profiles": Custom site profile definitions (each must extend a built-in profile)
|
|
17
|
+
* - "domains": Domain-to-profile mappings (can reference built-in or user profiles)
|
|
18
|
+
*
|
|
19
|
+
* User profiles cannot extend other user profiles — only built-in profiles. This prevents cascading breakage when a referenced user profile is deleted.
|
|
20
|
+
*/
|
|
21
|
+
// Valid SiteProfile behavior flag names that users can set. Metadata fields (category, description, extends, summary) are handled separately.
|
|
22
|
+
const VALID_PROFILE_FLAGS = new Set([
|
|
23
|
+
"channelSelector", "clickSelector", "clickToPlay", "fullscreenKey", "fullscreenSelector", "hideSelector", "lockVolumeProperties",
|
|
24
|
+
"needsIframeHandling", "noVideo", "selectReadyVideo", "useRequestFullscreen", "waitForNetworkIdle"
|
|
25
|
+
]);
|
|
26
|
+
// Generic strategies available for user profiles. Provider-specific strategies are built-in implementations and cannot be used by user profiles.
|
|
27
|
+
const GENERIC_STRATEGIES = new Set(["none", "thumbnailRow", "tileClick"]);
|
|
28
|
+
// All recognized strategy names (generic + provider-specific). Used for validation error messages.
|
|
29
|
+
const ALL_STRATEGIES = new Set(["foxGrid", "guideGrid", "hboGrid", "none", "slingGrid", "thumbnailRow", "tileClick", "youtubeGrid"]);
|
|
30
|
+
// Strategies that require a matchSelector to identify channel elements.
|
|
31
|
+
const STRATEGIES_REQUIRING_MATCH_SELECTOR = new Set(["thumbnailRow", "tileClick"]);
|
|
32
|
+
// Site-specific profiles that cannot be used as a base for user-defined profiles. These profiles have strategies, selectors, or flags tightly coupled to a specific
|
|
33
|
+
// streaming service's DOM structure. Users targeting these services should use the predefined channels directly, not create custom profiles extending them.
|
|
34
|
+
export const EXCLUDED_PROFILES = new Set(["disneyNow", "disneyPlus", "foxLive", "hboMax", "huluLive", "slingLive", "youtubeTV"]);
|
|
35
|
+
// Module-level storage for loaded user profiles and domains. Populated at startup and updated on save.
|
|
36
|
+
let loadedUserProfiles = {};
|
|
37
|
+
let loadedUserDomains = {};
|
|
38
|
+
let userProfilesParseError = false;
|
|
39
|
+
let userProfilesParseErrorMessage;
|
|
40
|
+
/**
|
|
41
|
+
* Returns whether the user profiles file had a parse error.
|
|
42
|
+
* @returns True if the profiles file exists but contains invalid JSON.
|
|
43
|
+
*/
|
|
44
|
+
export function hasProfilesParseError() {
|
|
45
|
+
return userProfilesParseError;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Returns the parse error message if the profiles file had a parse error.
|
|
49
|
+
* @returns The error message or undefined.
|
|
50
|
+
*/
|
|
51
|
+
export function getProfilesParseErrorMessage() {
|
|
52
|
+
return userProfilesParseErrorMessage;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Returns a copy of the loaded user profiles.
|
|
56
|
+
* @returns Record of profile names to SiteProfile definitions.
|
|
57
|
+
*/
|
|
58
|
+
export function getUserProfiles() {
|
|
59
|
+
return { ...loadedUserProfiles };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Returns a copy of the loaded user domain mappings.
|
|
63
|
+
* @returns Record of domain hostnames to DomainConfig entries.
|
|
64
|
+
*/
|
|
65
|
+
export function getUserDomains() {
|
|
66
|
+
return { ...loadedUserDomains };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Loads user profiles and domain mappings from the profiles file. Returns empty objects if the file doesn't exist, and sets parseError if the file exists but
|
|
70
|
+
* contains invalid JSON.
|
|
71
|
+
* @returns The loaded profiles and domains with parse status.
|
|
72
|
+
*/
|
|
73
|
+
export async function loadUserProfiles() {
|
|
74
|
+
try {
|
|
75
|
+
const content = await fsPromises.readFile(getProfilesFilePath(), "utf-8");
|
|
76
|
+
try {
|
|
77
|
+
// Parse as an untyped record to manually validate structure before assigning to typed interfaces.
|
|
78
|
+
const parsed = JSON.parse(content);
|
|
79
|
+
const profiles = {};
|
|
80
|
+
const domains = {};
|
|
81
|
+
// Extract profiles if present and valid.
|
|
82
|
+
const rawProfiles = parsed.profiles;
|
|
83
|
+
if ((typeof rawProfiles === "object") && (rawProfiles !== null) && !Array.isArray(rawProfiles)) {
|
|
84
|
+
for (const [key, value] of Object.entries(rawProfiles)) {
|
|
85
|
+
if ((typeof value === "object") && (value !== null) && !Array.isArray(value)) {
|
|
86
|
+
profiles[key] = value;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Extract domains if present and valid.
|
|
91
|
+
const rawDomains = parsed.domains;
|
|
92
|
+
if ((typeof rawDomains === "object") && (rawDomains !== null) && !Array.isArray(rawDomains)) {
|
|
93
|
+
for (const [key, value] of Object.entries(rawDomains)) {
|
|
94
|
+
if ((typeof value === "object") && (value !== null) && !Array.isArray(value)) {
|
|
95
|
+
domains[key] = value;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return { domains, parseError: false, profiles };
|
|
100
|
+
}
|
|
101
|
+
catch (parseError) {
|
|
102
|
+
const message = (parseError instanceof Error) ? parseError.message : String(parseError);
|
|
103
|
+
LOG.warn("Invalid JSON in profiles file %s: %s. Skipping user profiles.", getProfilesFilePath(), message);
|
|
104
|
+
return { domains: {}, parseError: true, parseErrorMessage: message, profiles: {} };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
// File doesn't exist — this is normal, no user profiles defined.
|
|
109
|
+
if (error.code === "ENOENT") {
|
|
110
|
+
return { domains: {}, parseError: false, profiles: {} };
|
|
111
|
+
}
|
|
112
|
+
// Other read errors — log and skip user profiles.
|
|
113
|
+
LOG.warn("Failed to read profiles file %s: %s. Skipping user profiles.", getProfilesFilePath(), (error instanceof Error) ? error.message : String(error));
|
|
114
|
+
return { domains: {}, parseError: false, profiles: {} };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Saves user profiles and domain mappings to the profiles file and updates the in-memory cache. Creates the data directory if it doesn't exist. Keys are sorted
|
|
119
|
+
* for consistent output.
|
|
120
|
+
* @param profiles - The profiles to save.
|
|
121
|
+
* @param domains - The domain mappings to save.
|
|
122
|
+
* @throws If the file cannot be written.
|
|
123
|
+
*/
|
|
124
|
+
export async function saveUserProfiles(profiles, domains) {
|
|
125
|
+
// Ensure data directory exists.
|
|
126
|
+
await fsPromises.mkdir(getDataDir(), { recursive: true });
|
|
127
|
+
// Build the file contents with sorted keys for consistent output.
|
|
128
|
+
const file = {};
|
|
129
|
+
// Only include sections that have entries.
|
|
130
|
+
const sortedDomainKeys = Object.keys(domains).sort();
|
|
131
|
+
const sortedProfileKeys = Object.keys(profiles).sort();
|
|
132
|
+
if (sortedDomainKeys.length > 0) {
|
|
133
|
+
const sortedDomains = {};
|
|
134
|
+
for (const key of sortedDomainKeys) {
|
|
135
|
+
sortedDomains[key] = domains[key];
|
|
136
|
+
}
|
|
137
|
+
file.domains = sortedDomains;
|
|
138
|
+
}
|
|
139
|
+
if (sortedProfileKeys.length > 0) {
|
|
140
|
+
const sortedProfiles = {};
|
|
141
|
+
for (const key of sortedProfileKeys) {
|
|
142
|
+
sortedProfiles[key] = profiles[key];
|
|
143
|
+
}
|
|
144
|
+
file.profiles = sortedProfiles;
|
|
145
|
+
}
|
|
146
|
+
// Write with pretty formatting for readability.
|
|
147
|
+
const content = JSON.stringify(file, null, 2);
|
|
148
|
+
await fsPromises.writeFile(getProfilesFilePath(), content + "\n", "utf-8");
|
|
149
|
+
// Update in-memory cache.
|
|
150
|
+
loadedUserProfiles = { ...profiles };
|
|
151
|
+
loadedUserDomains = { ...domains };
|
|
152
|
+
// Clear any previous parse error.
|
|
153
|
+
userProfilesParseError = false;
|
|
154
|
+
userProfilesParseErrorMessage = undefined;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Deletes a user profile by key and removes any domain mappings that reference it. Reloads the file from disk before modifying to avoid data loss.
|
|
158
|
+
* @param key - The profile key to delete.
|
|
159
|
+
* @throws If the file cannot be read or written.
|
|
160
|
+
*/
|
|
161
|
+
export async function deleteUserProfile(key) {
|
|
162
|
+
const result = await loadUserProfiles();
|
|
163
|
+
if (result.parseError) {
|
|
164
|
+
throw new Error("Cannot delete profile: profiles file contains invalid JSON.");
|
|
165
|
+
}
|
|
166
|
+
// Remove the profile.
|
|
167
|
+
Reflect.deleteProperty(result.profiles, key);
|
|
168
|
+
// Remove any domain mappings that reference this profile.
|
|
169
|
+
for (const [domain, config] of Object.entries(result.domains)) {
|
|
170
|
+
if (config.profile === key) {
|
|
171
|
+
Reflect.deleteProperty(result.domains, domain);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
await saveUserProfiles(result.profiles, result.domains);
|
|
175
|
+
LOG.info("User profile '%s' deleted.", key);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Deletes a single user domain mapping. Reloads the file from disk before modifying to avoid data loss.
|
|
179
|
+
* @param domain - The domain hostname to remove.
|
|
180
|
+
* @throws If the file cannot be read or written.
|
|
181
|
+
*/
|
|
182
|
+
export async function deleteUserDomain(domain) {
|
|
183
|
+
const result = await loadUserProfiles();
|
|
184
|
+
if (result.parseError) {
|
|
185
|
+
throw new Error("Cannot delete domain: profiles file contains invalid JSON.");
|
|
186
|
+
}
|
|
187
|
+
Reflect.deleteProperty(result.domains, domain);
|
|
188
|
+
await saveUserProfiles(result.profiles, result.domains);
|
|
189
|
+
LOG.info("User domain mapping '%s' deleted.", domain);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Initializes user profiles by loading them from the file. Called once at server startup before profile validation and channel loading.
|
|
193
|
+
*/
|
|
194
|
+
export async function initializeUserProfiles() {
|
|
195
|
+
const result = await loadUserProfiles();
|
|
196
|
+
loadedUserProfiles = result.profiles;
|
|
197
|
+
loadedUserDomains = result.domains;
|
|
198
|
+
userProfilesParseError = result.parseError;
|
|
199
|
+
userProfilesParseErrorMessage = result.parseErrorMessage;
|
|
200
|
+
// Check for non-printable characters in loaded profile and domain string values. These warnings are informational — loaded data is not modified.
|
|
201
|
+
for (const [profileKey, profile] of Object.entries(loadedUserProfiles)) {
|
|
202
|
+
for (const [field, value] of Object.entries(profile)) {
|
|
203
|
+
if ((typeof value === "string") && containsNonPrintable(value)) {
|
|
204
|
+
LOG.warn("User profile '%s' field '%s' contains non-printable characters. Re-save the profile to clean it.", profileKey, field);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
for (const [domain, config] of Object.entries(loadedUserDomains)) {
|
|
209
|
+
for (const [field, value] of Object.entries(config)) {
|
|
210
|
+
if ((typeof value === "string") && containsNonPrintable(value)) {
|
|
211
|
+
LOG.warn("User domain '%s' field '%s' contains non-printable characters. Re-save the domain mapping to clean it.", domain, field);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const profileCount = Object.keys(loadedUserProfiles).length;
|
|
216
|
+
const domainCount = Object.keys(loadedUserDomains).length;
|
|
217
|
+
if ((profileCount > 0) || (domainCount > 0)) {
|
|
218
|
+
LOG.info("Loaded %d user profile(s) and %d domain mapping(s).", profileCount, domainCount);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Validation Functions.
|
|
222
|
+
/**
|
|
223
|
+
* Validates a profile key for format, length, and uniqueness against built-in profiles.
|
|
224
|
+
* @param key - The profile key to validate.
|
|
225
|
+
* @param isNew - True if this is a new profile (checks for duplicates among user profiles).
|
|
226
|
+
* @returns Error message if invalid, undefined if valid.
|
|
227
|
+
*/
|
|
228
|
+
export function validateProfileKey(key, isNew) {
|
|
229
|
+
if (!key || (key.trim() === "")) {
|
|
230
|
+
return "Profile key is required.";
|
|
231
|
+
}
|
|
232
|
+
// Check format: must start with a letter, then letters, digits, and hyphens. Must not end with a hyphen. Profile keys follow camelCase convention but we also
|
|
233
|
+
// allow hyphens for user profiles.
|
|
234
|
+
if (!/^[a-zA-Z]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(key)) {
|
|
235
|
+
return "Profile key must start with a letter, contain only letters, numbers, and hyphens, and not end with a hyphen.";
|
|
236
|
+
}
|
|
237
|
+
if (key.length > 50) {
|
|
238
|
+
return "Profile key must be 50 characters or less.";
|
|
239
|
+
}
|
|
240
|
+
// Built-in profile keys are reserved.
|
|
241
|
+
if (key in SITE_PROFILES) {
|
|
242
|
+
return "Profile key '" + key + "' conflicts with a built-in profile. Choose a different name.";
|
|
243
|
+
}
|
|
244
|
+
// Check for duplicates when adding a new profile.
|
|
245
|
+
if (isNew && (key in loadedUserProfiles)) {
|
|
246
|
+
return "A user profile with this key already exists.";
|
|
247
|
+
}
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Validates a user-defined site profile. Checks that extends references a built-in profile, strategy is recognized and generic, matchSelector is present when
|
|
252
|
+
* required, and all flag names are valid SiteProfile fields.
|
|
253
|
+
* @param key - The profile key (for error messages).
|
|
254
|
+
* @param profile - The profile definition to validate.
|
|
255
|
+
* @returns Array of error messages (empty if valid).
|
|
256
|
+
*/
|
|
257
|
+
export function validateProfile(key, profile) {
|
|
258
|
+
const errors = [];
|
|
259
|
+
// The extends field is required for user profiles — they must build on a built-in profile.
|
|
260
|
+
if (!profile.extends) {
|
|
261
|
+
errors.push("Profile '" + key + "': extends is required. User profiles must extend a built-in profile.");
|
|
262
|
+
return errors;
|
|
263
|
+
}
|
|
264
|
+
// extends must reference a built-in profile (not another user profile).
|
|
265
|
+
if (!(profile.extends in SITE_PROFILES)) {
|
|
266
|
+
errors.push("Profile '" + key + "': extends references non-existent built-in profile '" + profile.extends + "'.");
|
|
267
|
+
}
|
|
268
|
+
else if (EXCLUDED_PROFILES.has(profile.extends)) {
|
|
269
|
+
// Site-specific profiles are tightly coupled to a streaming service's DOM structure and cannot be meaningfully extended by user profiles.
|
|
270
|
+
errors.push("Profile '" + key + "': '" + profile.extends + "' is a site-specific profile and cannot be extended. " +
|
|
271
|
+
"Use the predefined channels for this service instead.");
|
|
272
|
+
}
|
|
273
|
+
// Validate channel selection configuration if present.
|
|
274
|
+
if (profile.channelSelection) {
|
|
275
|
+
const strategy = profile.channelSelection.strategy;
|
|
276
|
+
if (!ALL_STRATEGIES.has(strategy)) {
|
|
277
|
+
errors.push("Profile '" + key + "': unrecognized channel selection strategy '" + strategy + "'.");
|
|
278
|
+
}
|
|
279
|
+
else if (!GENERIC_STRATEGIES.has(strategy)) {
|
|
280
|
+
errors.push("Profile '" + key + "': strategy '" + strategy + "' is a built-in provider strategy and cannot be used by user profiles. " +
|
|
281
|
+
"Use 'tileClick', 'thumbnailRow', or 'none'.");
|
|
282
|
+
}
|
|
283
|
+
// matchSelector is required for tileClick and thumbnailRow strategies.
|
|
284
|
+
if (STRATEGIES_REQUIRING_MATCH_SELECTOR.has(strategy) && !profile.channelSelection.matchSelector) {
|
|
285
|
+
errors.push("Profile '" + key + "': matchSelector is required when using the '" + strategy + "' strategy.");
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
// Validate that all remaining top-level fields are recognized SiteProfile behavior flags. Fields validated separately above (channelSelection) and metadata-only
|
|
289
|
+
// fields (category, description, extends, summary) are excluded from this check.
|
|
290
|
+
const handledFields = new Set(["category", "channelSelection", "description", "extends", "summary"]);
|
|
291
|
+
for (const field of Object.keys(profile)) {
|
|
292
|
+
if (!handledFields.has(field) && !VALID_PROFILE_FLAGS.has(field)) {
|
|
293
|
+
errors.push("Profile '" + key + "': unrecognized flag '" + field + "'.");
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return errors;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Validates a domain mapping. Checks hostname format, profile references, provider/providerTag strings, loginUrl format, and maxContinuousPlayback type and range.
|
|
300
|
+
* @param domain - The domain hostname.
|
|
301
|
+
* @param config - The domain configuration.
|
|
302
|
+
* @param availableProfiles - Set of available profile names (built-in + user, including profiles in the same import batch).
|
|
303
|
+
* @returns Array of error messages (empty if valid).
|
|
304
|
+
*/
|
|
305
|
+
export function validateDomain(domain, config, availableProfiles) {
|
|
306
|
+
const errors = [];
|
|
307
|
+
// Validate domain is a plausible hostname.
|
|
308
|
+
if (!domain || (domain.trim() === "")) {
|
|
309
|
+
errors.push("Domain is required.");
|
|
310
|
+
return errors;
|
|
311
|
+
}
|
|
312
|
+
// Basic hostname format check: must have at least one dot and contain only valid characters.
|
|
313
|
+
if (!/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}$/.test(domain)) {
|
|
314
|
+
errors.push("Domain '" + domain + "': invalid hostname format.");
|
|
315
|
+
}
|
|
316
|
+
// Reject domains that collide with built-in domain mappings. User domains that shadow built-in domains cause the built-in provider to disappear from the system,
|
|
317
|
+
// affecting all channels on that domain. Users should set the profile field on individual channels to use a custom profile on a built-in domain instead.
|
|
318
|
+
const conciseDomain = extractDomain("https://" + domain);
|
|
319
|
+
const collidesWithBuiltin = DOMAIN_CONFIG[domain] ?? DOMAIN_CONFIG[conciseDomain];
|
|
320
|
+
if (collidesWithBuiltin) {
|
|
321
|
+
const builtinProvider = collidesWithBuiltin.provider ?? conciseDomain;
|
|
322
|
+
errors.push("Domain '" + domain + "' is already mapped to built-in provider '" + builtinProvider +
|
|
323
|
+
"'. Set the profile field on individual channels to use your custom profile instead.");
|
|
324
|
+
}
|
|
325
|
+
// profile must reference an existing profile if specified.
|
|
326
|
+
if (config.profile && !availableProfiles.has(config.profile)) {
|
|
327
|
+
errors.push("Domain '" + domain + "': references non-existent profile '" + config.profile + "'.");
|
|
328
|
+
}
|
|
329
|
+
// provider must be non-empty if specified.
|
|
330
|
+
if ((config.provider !== undefined) && ((typeof config.provider !== "string") || (config.provider.trim() === ""))) {
|
|
331
|
+
errors.push("Domain '" + domain + "': provider must be a non-empty string.");
|
|
332
|
+
}
|
|
333
|
+
// providerTag must be non-empty if specified.
|
|
334
|
+
if ((config.providerTag !== undefined) && ((typeof config.providerTag !== "string") || (config.providerTag.trim() === ""))) {
|
|
335
|
+
errors.push("Domain '" + domain + "': providerTag must be a non-empty string.");
|
|
336
|
+
}
|
|
337
|
+
// loginUrl must be a valid http/https URL if specified.
|
|
338
|
+
if (config.loginUrl !== undefined) {
|
|
339
|
+
if ((typeof config.loginUrl !== "string") || (config.loginUrl.trim() === "")) {
|
|
340
|
+
errors.push("Domain '" + domain + "': loginUrl must be a non-empty string.");
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
try {
|
|
344
|
+
const parsed = new URL(config.loginUrl);
|
|
345
|
+
if ((parsed.protocol !== "http:") && (parsed.protocol !== "https:")) {
|
|
346
|
+
errors.push("Domain '" + domain + "': loginUrl must use http or https protocol.");
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
errors.push("Domain '" + domain + "': loginUrl is not a valid URL.");
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
// maxContinuousPlayback must be a positive number if specified.
|
|
355
|
+
if (config.maxContinuousPlayback !== undefined) {
|
|
356
|
+
if ((typeof config.maxContinuousPlayback !== "number") || !Number.isFinite(config.maxContinuousPlayback) ||
|
|
357
|
+
(config.maxContinuousPlayback <= 0)) {
|
|
358
|
+
errors.push("Domain '" + domain + "': maxContinuousPlayback must be a positive number.");
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return errors;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Validates an entire import batch of profiles and domains. Returns the validated entries and any errors found. Used by both file import and provider pack import.
|
|
365
|
+
* @param data - The raw data to validate (profiles and/or domains).
|
|
366
|
+
* @returns Validation result with validated entries and errors.
|
|
367
|
+
*/
|
|
368
|
+
export function validateImportedProfiles(data) {
|
|
369
|
+
const errors = [];
|
|
370
|
+
const validProfiles = {};
|
|
371
|
+
const validDomains = {};
|
|
372
|
+
if ((typeof data !== "object") || (data === null) || Array.isArray(data)) {
|
|
373
|
+
return { domains: {}, errors: ["Invalid format: expected an object with profiles and/or domains."], profiles: {}, valid: false };
|
|
374
|
+
}
|
|
375
|
+
const parsed = data;
|
|
376
|
+
// Validate profiles.
|
|
377
|
+
if (parsed.profiles) {
|
|
378
|
+
if ((typeof parsed.profiles !== "object") || Array.isArray(parsed.profiles)) {
|
|
379
|
+
errors.push("Invalid profiles field: expected an object.");
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
for (const [key, profile] of Object.entries(parsed.profiles)) {
|
|
383
|
+
// Check key format.
|
|
384
|
+
const keyError = validateProfileKey(key, false);
|
|
385
|
+
if (keyError) {
|
|
386
|
+
errors.push("Profile '" + key + "': " + keyError);
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
// Validate profile content.
|
|
390
|
+
const profileErrors = validateProfile(key, profile);
|
|
391
|
+
if (profileErrors.length > 0) {
|
|
392
|
+
errors.push(...profileErrors);
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
validProfiles[key] = profile;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
// Build the set of available profile names for domain validation: built-in profiles + successfully validated user profiles from this import + existing user
|
|
400
|
+
// profiles.
|
|
401
|
+
const availableProfiles = new Set([
|
|
402
|
+
...Object.keys(SITE_PROFILES),
|
|
403
|
+
...Object.keys(validProfiles),
|
|
404
|
+
...Object.keys(loadedUserProfiles)
|
|
405
|
+
]);
|
|
406
|
+
// Validate domains.
|
|
407
|
+
if (parsed.domains) {
|
|
408
|
+
if ((typeof parsed.domains !== "object") || Array.isArray(parsed.domains)) {
|
|
409
|
+
errors.push("Invalid domains field: expected an object.");
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
for (const [domain, config] of Object.entries(parsed.domains)) {
|
|
413
|
+
const domainErrors = validateDomain(domain, config, availableProfiles);
|
|
414
|
+
if (domainErrors.length > 0) {
|
|
415
|
+
errors.push(...domainErrors);
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
validDomains[domain] = config;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return { domains: validDomains, errors, profiles: validProfiles, valid: errors.length === 0 };
|
|
423
|
+
}
|
|
424
|
+
//# sourceMappingURL=userProfiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"userProfiles.js","sourceRoot":"","sources":["../../src/config/userProfiles.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE1D,OAAO,EAAE,GAAG,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;AAEpC;;;;;;;;;GASG;AAEH,8IAA8I;AAC9I,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,iBAAiB,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,oBAAoB,EAAE,cAAc,EAAE,sBAAsB;IAChI,qBAAqB,EAAE,SAAS,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,oBAAoB;CACnG,CAAC,CAAC;AAEH,iJAAiJ;AACjJ,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAE,MAAM,EAAE,cAAc,EAAE,WAAW,CAAE,CAAC,CAAC;AAE5E,mGAAmG;AACnG,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,aAAa,CAAE,CAAC,CAAC;AAEvI,wEAAwE;AACxE,MAAM,mCAAmC,GAAG,IAAI,GAAG,CAAC,CAAE,cAAc,EAAE,WAAW,CAAE,CAAC,CAAC;AAErF,oKAAoK;AACpK,4JAA4J;AAC5J,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,CAAE,CAAC,CAAC;AAEnI,uGAAuG;AACvG,IAAI,kBAAkB,GAAgC,EAAE,CAAC;AACzD,IAAI,iBAAiB,GAAiC,EAAE,CAAC;AACzD,IAAI,sBAAsB,GAAG,KAAK,CAAC;AACnC,IAAI,6BAAiD,CAAC;AAEtD;;;GAGG;AACH,MAAM,UAAU,qBAAqB;IAEnC,OAAO,sBAAsB,CAAC;AAChC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,4BAA4B;IAE1C,OAAO,6BAA6B,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe;IAE7B,OAAO,EAAE,GAAG,kBAAkB,EAAE,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc;IAE5B,OAAO,EAAE,GAAG,iBAAiB,EAAE,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IAEpC,IAAI,CAAC;QAEH,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,mBAAmB,EAAE,EAAE,OAAO,CAAC,CAAC;QAE1E,IAAI,CAAC;YAEH,kGAAkG;YAClG,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA4B,CAAC;YAE9D,MAAM,QAAQ,GAAgC,EAAE,CAAC;YACjD,MAAM,OAAO,GAAiC,EAAE,CAAC;YAEjD,yCAAyC;YACzC,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC;YAEpC,IAAG,CAAC,OAAO,WAAW,KAAK,QAAQ,CAAC,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;gBAE9F,KAAI,MAAM,CAAE,GAAG,EAAE,KAAK,CAAE,IAAI,MAAM,CAAC,OAAO,CAAC,WAAsC,CAAC,EAAE,CAAC;oBAEnF,IAAG,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;wBAE5E,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAoB,CAAC;oBACvC,CAAC;gBACH,CAAC;YACH,CAAC;YAED,wCAAwC;YACxC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC;YAElC,IAAG,CAAC,OAAO,UAAU,KAAK,QAAQ,CAAC,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;gBAE3F,KAAI,MAAM,CAAE,GAAG,EAAE,KAAK,CAAE,IAAI,MAAM,CAAC,OAAO,CAAC,UAAqC,CAAC,EAAE,CAAC;oBAElF,IAAG,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;wBAE5E,OAAO,CAAC,GAAG,CAAC,GAAG,KAAqB,CAAC;oBACvC,CAAC;gBACH,CAAC;YACH,CAAC;YAED,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;QAClD,CAAC;QAAC,OAAM,UAAU,EAAE,CAAC;YAEnB,MAAM,OAAO,GAAG,CAAC,UAAU,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAExF,GAAG,CAAC,IAAI,CAAC,+DAA+D,EAAE,mBAAmB,EAAE,EAAE,OAAO,CAAC,CAAC;YAE1G,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACrF,CAAC;IACH,CAAC;IAAC,OAAM,KAAK,EAAE,CAAC;QAEd,iEAAiE;QACjE,IAAI,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAEtD,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QAC1D,CAAC;QAED,kDAAkD;QAClD,GAAG,CAAC,IAAI,CAAC,8DAA8D,EAAE,mBAAmB,EAAE,EAAE,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAE1J,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC1D,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAqC,EAAE,OAAqC;IAEjH,gCAAgC;IAChC,MAAM,UAAU,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1D,kEAAkE;IAClE,MAAM,IAAI,GAAqB,EAAE,CAAC;IAElC,2CAA2C;IAC3C,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACrD,MAAM,iBAAiB,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;IAEvD,IAAG,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAE/B,MAAM,aAAa,GAAiC,EAAE,CAAC;QAEvD,KAAI,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;YAElC,aAAa,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,aAAa,CAAC;IAC/B,CAAC;IAED,IAAG,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAEhC,MAAM,cAAc,GAAgC,EAAE,CAAC;QAEvD,KAAI,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;YAEnC,cAAc,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC;QAED,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC;IACjC,CAAC;IAED,gDAAgD;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAE9C,MAAM,UAAU,CAAC,SAAS,CAAC,mBAAmB,EAAE,EAAE,OAAO,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAE3E,0BAA0B;IAC1B,kBAAkB,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;IACrC,iBAAiB,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IAEnC,kCAAkC;IAClC,sBAAsB,GAAG,KAAK,CAAC;IAC/B,6BAA6B,GAAG,SAAS,CAAC;AAC5C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAW;IAEjD,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAExC,IAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QAErB,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IAED,sBAAsB;IACtB,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAE7C,0DAA0D;IAC1D,KAAI,MAAM,CAAE,MAAM,EAAE,MAAM,CAAE,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAE/D,IAAG,MAAM,CAAC,OAAO,KAAK,GAAG,EAAE,CAAC;YAE1B,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAED,MAAM,gBAAgB,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAExD,GAAG,CAAC,IAAI,CAAC,4BAA4B,EAAE,GAAG,CAAC,CAAC;AAC9C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAc;IAEnD,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAExC,IAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QAErB,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAChF,CAAC;IAED,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAE/C,MAAM,gBAAgB,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAExD,GAAG,CAAC,IAAI,CAAC,mCAAmC,EAAE,MAAM,CAAC,CAAC;AACxD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAE1C,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAExC,kBAAkB,GAAG,MAAM,CAAC,QAAQ,CAAC;IACrC,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;IACnC,sBAAsB,GAAG,MAAM,CAAC,UAAU,CAAC;IAC3C,6BAA6B,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAEzD,iJAAiJ;IACjJ,KAAI,MAAM,CAAE,UAAU,EAAE,OAAO,CAAE,IAAI,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAExE,KAAI,MAAM,CAAE,KAAK,EAAE,KAAK,CAAE,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAEtD,IAAG,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAE9D,GAAG,CAAC,IAAI,CAAC,kGAAkG,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;YAClI,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAI,MAAM,CAAE,MAAM,EAAE,MAAM,CAAE,IAAI,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAElE,KAAI,MAAM,CAAE,KAAK,EAAE,KAAK,CAAE,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAErD,IAAG,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAE9D,GAAG,CAAC,IAAI,CAAC,wGAAwG,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;YACpI,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC;IAC5D,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC;IAE1D,IAAG,CAAC,YAAY,GAAG,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,EAAE,CAAC;QAE3C,GAAG,CAAC,IAAI,CAAC,qDAAqD,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;IAC7F,CAAC;AACH,CAAC;AAED,wBAAwB;AAExB;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,KAAc;IAE5D,IAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAE/B,OAAO,0BAA0B,CAAC;IACpC,CAAC;IAED,8JAA8J;IAC9J,mCAAmC;IACnC,IAAG,CAAC,uCAAuC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAEtD,OAAO,8GAA8G,CAAC;IACxH,CAAC;IAED,IAAG,GAAG,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAEnB,OAAO,4CAA4C,CAAC;IACtD,CAAC;IAED,sCAAsC;IACtC,IAAG,GAAG,IAAI,aAAa,EAAE,CAAC;QAExB,OAAO,eAAe,GAAG,GAAG,GAAG,+DAA+D,CAAC;IACjG,CAAC;IAED,kDAAkD;IAClD,IAAG,KAAK,IAAI,CAAC,GAAG,IAAI,kBAAkB,CAAC,EAAE,CAAC;QAExC,OAAO,8CAA8C,CAAC;IACxD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,OAAoB;IAE/D,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,2FAA2F;IAC3F,IAAG,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAEpB,MAAM,CAAC,IAAI,CAAC,WAAW,GAAG,GAAG,GAAG,uEAAuE,CAAC,CAAC;QAEzG,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,wEAAwE;IACxE,IAAG,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,aAAa,CAAC,EAAE,CAAC;QAEvC,MAAM,CAAC,IAAI,CAAC,WAAW,GAAG,GAAG,GAAG,uDAAuD,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACpH,CAAC;SAAM,IAAG,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAEjD,0IAA0I;QAC1I,MAAM,CAAC,IAAI,CAAC,WAAW,GAAG,GAAG,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,uDAAuD;YAChH,uDAAuD,CAAC,CAAC;IAC7D,CAAC;IAED,uDAAuD;IACvD,IAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;QAE5B,MAAM,QAAQ,GAAG,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QAEnD,IAAG,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAEjC,MAAM,CAAC,IAAI,CAAC,WAAW,GAAG,GAAG,GAAG,8CAA8C,GAAG,QAAQ,GAAG,IAAI,CAAC,CAAC;QACpG,CAAC;aAAM,IAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAE5C,MAAM,CAAC,IAAI,CAAC,WAAW,GAAG,GAAG,GAAG,eAAe,GAAG,QAAQ,GAAG,yEAAyE;gBACpI,6CAA6C,CAAC,CAAC;QACnD,CAAC;QAED,uEAAuE;QACvE,IAAG,mCAAmC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,aAAa,EAAE,CAAC;YAEhG,MAAM,CAAC,IAAI,CAAC,WAAW,GAAG,GAAG,GAAG,+CAA+C,GAAG,QAAQ,GAAG,aAAa,CAAC,CAAC;QAC9G,CAAC;IACH,CAAC;IAED,iKAAiK;IACjK,iFAAiF;IACjF,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAE,UAAU,EAAE,kBAAkB,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,CAAE,CAAC,CAAC;IAEvG,KAAI,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAExC,IAAG,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAEhE,MAAM,CAAC,IAAI,CAAC,WAAW,GAAG,GAAG,GAAG,wBAAwB,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,MAAoB,EAAE,iBAA8B;IAEjG,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,2CAA2C;IAC3C,IAAG,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAErC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAEnC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,6FAA6F;IAC7F,IAAG,CAAC,mGAAmG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAErH,MAAM,CAAC,IAAI,CAAC,UAAU,GAAG,MAAM,GAAG,6BAA6B,CAAC,CAAC;IACnE,CAAC;IAED,iKAAiK;IACjK,yJAAyJ;IACzJ,MAAM,aAAa,GAAG,aAAa,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC;IACzD,MAAM,mBAAmB,GAAI,aAAa,CAAC,MAAM,CAA8B,IAAK,aAAa,CAAC,aAAa,CAA8B,CAAC;IAE9I,IAAG,mBAAmB,EAAE,CAAC;QAEvB,MAAM,eAAe,GAAG,mBAAmB,CAAC,QAAQ,IAAI,aAAa,CAAC;QAEtE,MAAM,CAAC,IAAI,CAAC,UAAU,GAAG,MAAM,GAAG,4CAA4C,GAAG,eAAe;YAC9F,qFAAqF,CAAC,CAAC;IAC3F,CAAC;IAED,2DAA2D;IAC3D,IAAG,MAAM,CAAC,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAE5D,MAAM,CAAC,IAAI,CAAC,UAAU,GAAG,MAAM,GAAG,sCAAsC,GAAG,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACpG,CAAC;IAED,2CAA2C;IAC3C,IAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;QAEjH,MAAM,CAAC,IAAI,CAAC,UAAU,GAAG,MAAM,GAAG,yCAAyC,CAAC,CAAC;IAC/E,CAAC;IAED,8CAA8C;IAC9C,IAAG,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;QAE1H,MAAM,CAAC,IAAI,CAAC,UAAU,GAAG,MAAM,GAAG,4CAA4C,CAAC,CAAC;IAClF,CAAC;IAED,wDAAwD;IACxD,IAAG,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAEjC,IAAG,CAAC,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;YAE5E,MAAM,CAAC,IAAI,CAAC,UAAU,GAAG,MAAM,GAAG,yCAAyC,CAAC,CAAC;QAC/E,CAAC;aAAM,CAAC;YAEN,IAAI,CAAC;gBAEH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAExC,IAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,EAAE,CAAC;oBAEnE,MAAM,CAAC,IAAI,CAAC,UAAU,GAAG,MAAM,GAAG,8CAA8C,CAAC,CAAC;gBACpF,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBAEP,MAAM,CAAC,IAAI,CAAC,UAAU,GAAG,MAAM,GAAG,iCAAiC,CAAC,CAAC;YACvE,CAAC;QACH,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,IAAG,MAAM,CAAC,qBAAqB,KAAK,SAAS,EAAE,CAAC;QAE9C,IAAG,CAAC,OAAO,MAAM,CAAC,qBAAqB,KAAK,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,qBAAqB,CAAC;YACrG,CAAC,MAAM,CAAC,qBAAqB,IAAI,CAAC,CAAC,EAAE,CAAC;YAEtC,MAAM,CAAC,IAAI,CAAC,UAAU,GAAG,MAAM,GAAG,qDAAqD,CAAC,CAAC;QAC3F,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAa;IAEpD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,aAAa,GAAgC,EAAE,CAAC;IACtD,MAAM,YAAY,GAAiC,EAAE,CAAC;IAEtD,IAAG,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAExE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,kEAAkE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IACnI,CAAC;IAED,MAAM,MAAM,GAAG,IAAwB,CAAC;IAExC,qBAAqB;IACrB,IAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;QAEnB,IAAG,CAAC,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YAE3E,MAAM,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;QAC7D,CAAC;aAAM,CAAC;YAEN,KAAI,MAAM,CAAE,GAAG,EAAE,OAAO,CAAE,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAE9D,oBAAoB;gBACpB,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;gBAEhD,IAAG,QAAQ,EAAE,CAAC;oBAEZ,MAAM,CAAC,IAAI,CAAC,WAAW,GAAG,GAAG,GAAG,KAAK,GAAG,QAAQ,CAAC,CAAC;oBAElD,SAAS;gBACX,CAAC;gBAED,4BAA4B;gBAC5B,MAAM,aAAa,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;gBAEpD,IAAG,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAE5B,MAAM,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;oBAE9B,SAAS;gBACX,CAAC;gBAED,aAAa,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;YAC/B,CAAC;QACH,CAAC;IACH,CAAC;IAED,4JAA4J;IAC5J,YAAY;IACZ,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;QAChC,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC;QAC7B,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC;QAC7B,GAAG,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC;KACnC,CAAC,CAAC;IAEH,oBAAoB;IACpB,IAAG,MAAM,CAAC,OAAO,EAAE,CAAC;QAElB,IAAG,CAAC,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAEzE,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAC5D,CAAC;aAAM,CAAC;YAEN,KAAI,MAAM,CAAE,MAAM,EAAE,MAAM,CAAE,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;gBAE/D,MAAM,YAAY,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC;gBAEvE,IAAG,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAE3B,MAAM,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;oBAE7B,SAAS;gBACX,CAAC;gBAED,YAAY,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;AAChG,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type { ChannelRowHtml } from "./table.js";
|
|
2
|
+
export { ICON_DELETE, ICON_EDIT, OPTIONAL_COLUMNS, VALID_OPTIONAL_COLUMNS, generateChannelRowHtml, generateChannelsPanel, generateProviderFilterToolbar } from "./table.js";
|
|
3
|
+
export { setupChannelRoutes } from "./routes.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/routes/config/channels/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,qBAAqB,EACtH,6BAA6B,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
|