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,573 @@
|
|
|
1
|
+
import { EXCLUDED_PROFILES, deleteUserProfile, getUserDomains, getUserProfiles, saveUserProfiles, validateDomain, validateProfile, validateProfileKey } from "../../config/userProfiles.js";
|
|
2
|
+
import { ICON_DELETE, ICON_EDIT } from "./channels/index.js";
|
|
3
|
+
import { LOG, escapeHtml, formatError, sanitizeString } from "../../utils/index.js";
|
|
4
|
+
import { exportProviderPack, importProviderPack, parseProviderPack } from "../../config/providerPacks.js";
|
|
5
|
+
import { getChannelListing, validateChannelUrl } from "../../config/userChannels.js";
|
|
6
|
+
import { categorizeProfiles } from "./index.js";
|
|
7
|
+
import { getProfiles } from "../../config/profiles.js";
|
|
8
|
+
/**
|
|
9
|
+
* Counts channels per user profile key by scanning the channel listing. Returns a record mapping profile key to channel count.
|
|
10
|
+
* @param profileKeys - The set of user profile keys to count channels for.
|
|
11
|
+
* @returns Record of profile key to channel count.
|
|
12
|
+
*/
|
|
13
|
+
function countChannelsByProfile(profileKeys) {
|
|
14
|
+
const counts = {};
|
|
15
|
+
const listing = getChannelListing();
|
|
16
|
+
for (const entry of listing) {
|
|
17
|
+
const prof = entry.channel.profile;
|
|
18
|
+
if (prof && profileKeys.has(prof)) {
|
|
19
|
+
counts[prof] = (counts[prof] ?? 0) + 1;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return counts;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Generates the Providers panel content for the Channels tab's Providers subtab. Shows a table of user-defined profiles with their domain mappings and delete
|
|
26
|
+
* buttons. The toolbar provides New Profile, Import, and Export actions. The profile builder wizard is triggered from the toolbar.
|
|
27
|
+
* @returns HTML content for the Providers panel.
|
|
28
|
+
*/
|
|
29
|
+
export function generateProvidersPanel() {
|
|
30
|
+
const userProfiles = getUserProfiles();
|
|
31
|
+
const userDomains = getUserDomains();
|
|
32
|
+
const lines = [];
|
|
33
|
+
// Panel description.
|
|
34
|
+
lines.push("<div class=\"settings-panel-description\">");
|
|
35
|
+
lines.push("<p>Define custom site profiles and domain mappings to add support for streaming providers not built into PrismCast.</p>");
|
|
36
|
+
lines.push("<p class=\"description-hint\">Tip: Use the <strong>Profile Builder</strong> wizard to create new profiles step by step, ");
|
|
37
|
+
lines.push("or <strong>Import</strong> a pre-made provider pack shared by others. User profiles extend built-in profiles and can override ");
|
|
38
|
+
lines.push("specific behaviors like channel selection strategy or playback controls.</p>");
|
|
39
|
+
lines.push("</div>");
|
|
40
|
+
// Toolbar with provider operations.
|
|
41
|
+
lines.push("<div class=\"channel-toolbar\">");
|
|
42
|
+
lines.push("<div class=\"toolbar-group\">");
|
|
43
|
+
lines.push("<button type=\"button\" class=\"btn btn-primary btn-sm\" onclick=\"openWizard()\">New Profile</button>");
|
|
44
|
+
lines.push("<button type=\"button\" class=\"btn btn-secondary btn-sm\" onclick=\"startProviderImport()\">Import</button>");
|
|
45
|
+
// Only show export when there are user profiles to export.
|
|
46
|
+
if (Object.keys(userProfiles).length > 0) {
|
|
47
|
+
lines.push("<button type=\"button\" class=\"btn btn-secondary btn-sm\" onclick=\"startProviderExport()\">Export</button>");
|
|
48
|
+
}
|
|
49
|
+
lines.push("</div>");
|
|
50
|
+
lines.push("</div>");
|
|
51
|
+
const profileKeys = Object.keys(userProfiles).sort();
|
|
52
|
+
// Import preview modal: shows pack contents with optional skip-channels toggle. Always rendered because import is available even when no profiles exist.
|
|
53
|
+
lines.push("<div id=\"import-modal\" class=\"wizard-modal\" style=\"display: none;\">");
|
|
54
|
+
lines.push("<div class=\"wizard-modal-content\" style=\"max-width: 480px;\">");
|
|
55
|
+
lines.push("<div class=\"wizard-header\">");
|
|
56
|
+
lines.push("<h3>Import Provider Pack</h3>");
|
|
57
|
+
lines.push("<button type=\"button\" class=\"wizard-close\" aria-label=\"Close\" onclick=\"closeImportModal()\">\u2715</button>");
|
|
58
|
+
lines.push("</div>");
|
|
59
|
+
lines.push("<div id=\"import-modal-body\" class=\"export-modal-body\"></div>");
|
|
60
|
+
lines.push("<div class=\"wizard-buttons\">");
|
|
61
|
+
lines.push("<button type=\"button\" class=\"btn btn-secondary\" onclick=\"closeImportModal()\">Cancel</button>");
|
|
62
|
+
lines.push("<div class=\"wizard-buttons-right\">");
|
|
63
|
+
lines.push("<button type=\"button\" id=\"import-btn\" class=\"btn btn-primary btn-sm\" onclick=\"executeImport()\">Import</button>");
|
|
64
|
+
lines.push("</div>");
|
|
65
|
+
lines.push("</div>");
|
|
66
|
+
lines.push("</div>");
|
|
67
|
+
lines.push("</div>");
|
|
68
|
+
// Empty state when no user providers are installed.
|
|
69
|
+
if (profileKeys.length === 0) {
|
|
70
|
+
lines.push("<div class=\"empty-state\">");
|
|
71
|
+
lines.push("<p class=\"empty-state-title\">No custom providers installed</p>");
|
|
72
|
+
lines.push("<p class=\"empty-state-text\">Custom providers let you add support for streaming sites not built into PrismCast. ");
|
|
73
|
+
lines.push("Click <strong>New Profile</strong> to create one using the step-by-step wizard, or <strong>Import</strong> a provider ");
|
|
74
|
+
lines.push("pack shared by another user.</p>");
|
|
75
|
+
lines.push("</div>");
|
|
76
|
+
return lines.join("\n");
|
|
77
|
+
}
|
|
78
|
+
// Build a reverse lookup: profile key → list of domains mapped to it.
|
|
79
|
+
const profileDomains = {};
|
|
80
|
+
for (const key of profileKeys) {
|
|
81
|
+
profileDomains[key] = [];
|
|
82
|
+
}
|
|
83
|
+
for (const [domain, config] of Object.entries(userDomains)) {
|
|
84
|
+
if (config.profile && (config.profile in userProfiles)) {
|
|
85
|
+
profileDomains[config.profile] ??= [];
|
|
86
|
+
profileDomains[config.profile].push({ domain, provider: config.provider, providerTag: config.providerTag });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Compute channel counts per profile key.
|
|
90
|
+
const channelCounts = countChannelsByProfile(new Set(profileKeys));
|
|
91
|
+
// Provider table.
|
|
92
|
+
lines.push("<table class=\"channel-table\">");
|
|
93
|
+
lines.push("<thead><tr>");
|
|
94
|
+
lines.push("<th>Profile</th>");
|
|
95
|
+
lines.push("<th>Provider</th>");
|
|
96
|
+
lines.push("<th>Base</th>");
|
|
97
|
+
lines.push("<th>Domains</th>");
|
|
98
|
+
lines.push("<th>Strategy</th>");
|
|
99
|
+
lines.push("<th>Channels</th>");
|
|
100
|
+
lines.push("<th class=\"actions-col\">Actions</th>");
|
|
101
|
+
lines.push("</tr></thead>");
|
|
102
|
+
lines.push("<tbody>");
|
|
103
|
+
for (const key of profileKeys) {
|
|
104
|
+
const profile = userProfiles[key];
|
|
105
|
+
const domains = profileDomains[key] ?? [];
|
|
106
|
+
const strategy = profile.channelSelection?.strategy ?? "inherited";
|
|
107
|
+
const count = channelCounts[key] ?? 0;
|
|
108
|
+
// Provider name: use the first non-empty provider name from domain mappings, or a placeholder if none.
|
|
109
|
+
const providerName = domains.find((d) => d.provider)?.provider;
|
|
110
|
+
const providerHtml = providerName ? escapeHtml(providerName) : "<span class=\"text-muted\">\u2014</span>";
|
|
111
|
+
// Domain list: show each mapped domain, or a placeholder if none.
|
|
112
|
+
const domainHtml = (domains.length > 0) ?
|
|
113
|
+
domains.map((d) => escapeHtml(d.domain)).join("<br>") :
|
|
114
|
+
"<span class=\"text-muted\">none</span>";
|
|
115
|
+
lines.push("<tr>");
|
|
116
|
+
lines.push("<td><strong>" + escapeHtml(key) + "</strong></td>");
|
|
117
|
+
lines.push("<td>" + providerHtml + "</td>");
|
|
118
|
+
lines.push("<td>" + escapeHtml(profile.extends ?? "\u2014") + "</td>");
|
|
119
|
+
lines.push("<td>" + domainHtml + "</td>");
|
|
120
|
+
lines.push("<td>" + escapeHtml(strategy) + "</td>");
|
|
121
|
+
lines.push("<td>" + String(count) + "</td>");
|
|
122
|
+
lines.push("<td class=\"actions-col\">");
|
|
123
|
+
lines.push("<div class=\"btn-group\">");
|
|
124
|
+
lines.push("<button type=\"button\" class=\"btn-icon btn-icon-edit\" title=\"Edit\" aria-label=\"Edit\" " +
|
|
125
|
+
"onclick=\"editUserProfile('" + escapeHtml(key) + "')\">" + ICON_EDIT + "</button>");
|
|
126
|
+
lines.push("<button type=\"button\" class=\"btn-icon btn-icon-delete\" title=\"Delete\" aria-label=\"Delete\" " +
|
|
127
|
+
"onclick=\"deleteUserProfile('" + escapeHtml(key) + "')\">" + ICON_DELETE + "</button>");
|
|
128
|
+
lines.push("</div>");
|
|
129
|
+
lines.push("</td>");
|
|
130
|
+
lines.push("</tr>");
|
|
131
|
+
}
|
|
132
|
+
lines.push("</tbody>");
|
|
133
|
+
lines.push("</table>");
|
|
134
|
+
// Export modal: profile checklist with select-all and include-channels toggle. The select-all row is hidden by client-side JavaScript when only one profile
|
|
135
|
+
// exists since it would be redundant with the single profile checkbox.
|
|
136
|
+
lines.push("<div id=\"export-modal\" class=\"wizard-modal\" style=\"display: none;\">");
|
|
137
|
+
lines.push("<div class=\"wizard-modal-content\" style=\"max-width: 480px;\">");
|
|
138
|
+
lines.push("<div class=\"wizard-header\">");
|
|
139
|
+
lines.push("<h3>Export Provider Profiles</h3>");
|
|
140
|
+
lines.push("<button type=\"button\" class=\"wizard-close\" aria-label=\"Close\" onclick=\"closeExportModal()\">\u2715</button>");
|
|
141
|
+
lines.push("</div>");
|
|
142
|
+
lines.push("<div class=\"export-modal-body\">");
|
|
143
|
+
lines.push("<div id=\"export-select-all-row\" class=\"export-section-header\">");
|
|
144
|
+
lines.push("<label class=\"export-option-label\">");
|
|
145
|
+
lines.push("<input type=\"checkbox\" id=\"export-select-all\" checked onchange=\"toggleExportAll(this)\"> Select all</label>");
|
|
146
|
+
lines.push("</div>");
|
|
147
|
+
lines.push("<div id=\"export-profile-list\"></div>");
|
|
148
|
+
lines.push("<div class=\"export-divider\"></div>");
|
|
149
|
+
lines.push("<label class=\"export-option-label\">");
|
|
150
|
+
lines.push("<input type=\"checkbox\" id=\"export-include-channels\"> Include channels</label>");
|
|
151
|
+
lines.push("<div class=\"export-hint\">Bundle the channel definitions assigned to these profiles so recipients can import a complete lineup.</div>");
|
|
152
|
+
lines.push("</div>");
|
|
153
|
+
lines.push("<div class=\"wizard-buttons\">");
|
|
154
|
+
lines.push("<button type=\"button\" class=\"btn btn-secondary\" onclick=\"closeExportModal()\">Cancel</button>");
|
|
155
|
+
lines.push("<div class=\"wizard-buttons-right\">");
|
|
156
|
+
lines.push("<button type=\"button\" id=\"export-btn\" class=\"btn btn-primary btn-sm\" onclick=\"executeExport()\">Export</button>");
|
|
157
|
+
lines.push("</div>");
|
|
158
|
+
lines.push("</div>");
|
|
159
|
+
lines.push("</div>");
|
|
160
|
+
lines.push("</div>");
|
|
161
|
+
return lines.join("\n");
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Generates the profile builder wizard modal HTML. The modal shell contains a step indicator, a dynamic content area (rendered by client-side JavaScript), and
|
|
165
|
+
* navigation buttons. Profile data for Step 1 is embedded as a JSON script block for the wizard JS to consume.
|
|
166
|
+
* @returns HTML string for the wizard modal.
|
|
167
|
+
*/
|
|
168
|
+
export function generateWizardModal() {
|
|
169
|
+
// Build the profile data for Step 1 radio buttons. Include all profiles (built-in and user-defined).
|
|
170
|
+
const profiles = getProfiles();
|
|
171
|
+
const groups = categorizeProfiles(profiles);
|
|
172
|
+
// Site-specific profiles are excluded from the wizard — they have strategies and selectors tightly coupled to a specific service's DOM structure. User-defined
|
|
173
|
+
// profiles are also excluded because chained extensions (custom B extends custom A extends built-in X) are not supported.
|
|
174
|
+
const include = (p) => !EXCLUDED_PROFILES.has(p.name) && (p.source === "builtin");
|
|
175
|
+
// Serialize profile groups as JSON for the wizard JavaScript. Each entry has name, description, and summary.
|
|
176
|
+
const profileData = {
|
|
177
|
+
api: groups.api.filter(include).map((p) => ({ description: p.description, name: p.name, summary: p.summary })),
|
|
178
|
+
custom: groups.custom.filter(include).map((p) => ({ description: p.description, name: p.name, summary: p.summary })),
|
|
179
|
+
keyboard: groups.keyboard.filter(include).map((p) => ({ description: p.description, name: p.name, summary: p.summary })),
|
|
180
|
+
multiChannel: groups.multiChannel.filter(include).map((p) => ({ description: p.description, name: p.name, summary: p.summary })),
|
|
181
|
+
special: groups.special.filter(include).map((p) => ({ description: p.description, name: p.name, summary: p.summary }))
|
|
182
|
+
};
|
|
183
|
+
const lines = [];
|
|
184
|
+
lines.push("<div id=\"wizard-modal\" class=\"wizard-modal\" style=\"display: none;\">");
|
|
185
|
+
lines.push("<div class=\"wizard-modal-content\">");
|
|
186
|
+
// Header with title and close button. The title is updated by JavaScript to reflect edit vs. new mode.
|
|
187
|
+
lines.push("<div class=\"wizard-header\">");
|
|
188
|
+
lines.push("<h3 id=\"wizard-title\">New Provider Profile</h3>");
|
|
189
|
+
lines.push("<button type=\"button\" class=\"wizard-close\" aria-label=\"Close\" onclick=\"closeWizard()\">\u2715</button>");
|
|
190
|
+
lines.push("</div>");
|
|
191
|
+
// Step indicator.
|
|
192
|
+
lines.push("<div class=\"wizard-steps\">");
|
|
193
|
+
lines.push("<div class=\"wizard-step active\" data-step=\"1\"><span class=\"step-circle\">1</span><span class=\"step-label\">Base</span></div>");
|
|
194
|
+
lines.push("<div class=\"wizard-step-line\"></div>");
|
|
195
|
+
lines.push("<div class=\"wizard-step\" data-step=\"2\"><span class=\"step-circle\">2</span><span class=\"step-label\">Strategy</span></div>");
|
|
196
|
+
lines.push("<div class=\"wizard-step-line\"></div>");
|
|
197
|
+
lines.push("<div class=\"wizard-step\" data-step=\"3\"><span class=\"step-circle\">3</span><span class=\"step-label\">Flags</span></div>");
|
|
198
|
+
lines.push("<div class=\"wizard-step-line\"></div>");
|
|
199
|
+
lines.push("<div class=\"wizard-step\" data-step=\"4\"><span class=\"step-circle\">4</span><span class=\"step-label\">Domain</span></div>");
|
|
200
|
+
lines.push("<div class=\"wizard-step-line\"></div>");
|
|
201
|
+
lines.push("<div class=\"wizard-step\" data-step=\"5\"><span class=\"step-circle\">5</span><span class=\"step-label\">Save</span></div>");
|
|
202
|
+
lines.push("</div>");
|
|
203
|
+
// Dynamic content area — rendered by wizard JavaScript based on current step.
|
|
204
|
+
lines.push("<div id=\"wizard-content\" class=\"wizard-content\"></div>");
|
|
205
|
+
// Validation error area.
|
|
206
|
+
lines.push("<div id=\"wizard-error\" class=\"wizard-error\" style=\"display: none;\"></div>");
|
|
207
|
+
// Navigation buttons.
|
|
208
|
+
lines.push("<div class=\"wizard-buttons\">");
|
|
209
|
+
lines.push("<button type=\"button\" class=\"btn btn-secondary\" id=\"wizard-back\" onclick=\"wizardBack()\" style=\"display: none;\">Back</button>");
|
|
210
|
+
lines.push("<div class=\"wizard-buttons-right\">");
|
|
211
|
+
lines.push("<button type=\"button\" class=\"btn btn-secondary\" onclick=\"closeWizard()\">Cancel</button>");
|
|
212
|
+
lines.push("<button type=\"button\" class=\"btn btn-primary\" id=\"wizard-next\" onclick=\"wizardNext()\">Next</button>");
|
|
213
|
+
lines.push("<button type=\"button\" class=\"btn btn-primary\" id=\"wizard-save\" onclick=\"saveProfile(false)\" style=\"display: none;\">Save</button>");
|
|
214
|
+
lines.push("<button type=\"button\" class=\"btn btn-primary\" id=\"wizard-save-test\" onclick=\"saveProfile(true)\" ", "style=\"display: none;\">Save & Test</button>");
|
|
215
|
+
lines.push("</div>");
|
|
216
|
+
lines.push("</div>");
|
|
217
|
+
lines.push("</div>");
|
|
218
|
+
lines.push("</div>");
|
|
219
|
+
// Server-side registries for the wizard. Strategies define user-configurable channel selection approaches (provider-specific strategies like foxGrid, slingGrid,
|
|
220
|
+
// etc. are built-in only and never appear in the wizard). Flags define boolean profile flags exposed in step 3. Both are serialized as JSON so the wizard client
|
|
221
|
+
// code is fully data-driven — adding a new strategy field or flag only requires updating these arrays.
|
|
222
|
+
const WIZARD_STRATEGIES = [
|
|
223
|
+
{
|
|
224
|
+
description: "Click a channel tile, optionally click a play button.",
|
|
225
|
+
fields: [
|
|
226
|
+
{ hint: "Finds the channel element. Use {channel} as the placeholder for the channel selector value.", id: "matchSelector",
|
|
227
|
+
label: "Match Selector (CSS)", placeholder: "e.g., [style*=\"{channel}\"]", required: true, type: "text" },
|
|
228
|
+
{ hint: "Play button that appears after clicking the tile. Leave empty if the site auto-plays.", id: "playSelector",
|
|
229
|
+
label: "Play Selector (CSS)", placeholder: "e.g., [aria-label^=\"on now,\"]", required: false, type: "text" },
|
|
230
|
+
{ hint: "Scroll the page to the bottom before looking for channel tiles. Useful for lazy-loaded content.", id: "scrollToBottom",
|
|
231
|
+
label: "Scroll to bottom before selection", required: false, type: "boolean" }
|
|
232
|
+
],
|
|
233
|
+
id: "tileClick",
|
|
234
|
+
name: "Tile Click"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
description: "Match a channel thumbnail image, click adjacent entry.",
|
|
238
|
+
fields: [
|
|
239
|
+
{ hint: "Finds the channel element. Use {channel} as the placeholder for the channel selector value.", id: "matchSelector",
|
|
240
|
+
label: "Match Selector (CSS)", placeholder: "e.g., img[src*=\"{channel}\"]", required: true, type: "text" },
|
|
241
|
+
{ hint: "Play button that appears after clicking the thumbnail row. Leave empty if the site auto-plays.", id: "playSelector",
|
|
242
|
+
label: "Play Selector (CSS)", placeholder: "", required: false, type: "text" },
|
|
243
|
+
{ hint: "Scroll the page to the bottom before looking for channel thumbnails. Useful for lazy-loaded content.", id: "scrollToBottom",
|
|
244
|
+
label: "Scroll to bottom before selection", required: false, type: "boolean" }
|
|
245
|
+
],
|
|
246
|
+
id: "thumbnailRow",
|
|
247
|
+
name: "Thumbnail Row"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
description: "No channel selection needed.",
|
|
251
|
+
fields: [],
|
|
252
|
+
id: "none",
|
|
253
|
+
name: "None (single-channel site)"
|
|
254
|
+
}
|
|
255
|
+
];
|
|
256
|
+
const WIZARD_FLAGS = [
|
|
257
|
+
{ description: "Find video with readyState >= 3. For pages with multiple video elements.", id: "selectReadyVideo", label: "Select ready video" },
|
|
258
|
+
{ description: "Prevent the site from auto-muting.", id: "lockVolumeProperties", label: "Lock volume properties" },
|
|
259
|
+
{ description: "Click an element to start playback.", id: "clickToPlay", label: "Click to play" },
|
|
260
|
+
{ description: "Video is embedded in an iframe.", id: "needsIframeHandling", label: "Needs iframe handling" },
|
|
261
|
+
{ description: "Wait for network to settle before capture.", id: "waitForNetworkIdle", label: "Wait for network idle" },
|
|
262
|
+
{ description: "Force JavaScript requestFullscreen() API.", id: "useRequestFullscreen", label: "Use request fullscreen" }
|
|
263
|
+
];
|
|
264
|
+
// Embedded profile data and registries for the wizard JavaScript.
|
|
265
|
+
lines.push("<script>window.__wizardProfiles = " + JSON.stringify(profileData) + ";window.__wizardStrategies = " + JSON.stringify(WIZARD_STRATEGIES) +
|
|
266
|
+
";window.__wizardFlags = " + JSON.stringify(WIZARD_FLAGS) + ";</script>");
|
|
267
|
+
return lines.join("\n");
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Installs all profile-related route handlers on the Express application.
|
|
271
|
+
* @param app - The Express application.
|
|
272
|
+
*/
|
|
273
|
+
export function setupProfileRoutes(app) {
|
|
274
|
+
// GET /config/profiles - List user-defined profiles and domain mappings.
|
|
275
|
+
app.get("/config/profiles", (_req, res) => {
|
|
276
|
+
try {
|
|
277
|
+
const profiles = getUserProfiles();
|
|
278
|
+
const domains = getUserDomains();
|
|
279
|
+
// Compute channel counts per profile key.
|
|
280
|
+
const profileChannelCounts = countChannelsByProfile(new Set(Object.keys(profiles)));
|
|
281
|
+
// Build a summary for each profile including its domain mappings and channel count.
|
|
282
|
+
const profileList = Object.entries(profiles).sort(([a], [b]) => a.localeCompare(b)).map(([key, profile]) => {
|
|
283
|
+
// Find domains that reference this profile.
|
|
284
|
+
const profileDomains = Object.entries(domains).filter(([, config]) => (config.profile === key)).map(([domain, config]) => ({
|
|
285
|
+
domain,
|
|
286
|
+
provider: config.provider ?? "",
|
|
287
|
+
providerTag: config.providerTag ?? ""
|
|
288
|
+
}));
|
|
289
|
+
return {
|
|
290
|
+
channelCount: profileChannelCounts[key] ?? 0,
|
|
291
|
+
domains: profileDomains,
|
|
292
|
+
extends: profile.extends ?? "default",
|
|
293
|
+
key,
|
|
294
|
+
profile,
|
|
295
|
+
strategy: profile.channelSelection?.strategy ?? "inherited"
|
|
296
|
+
};
|
|
297
|
+
});
|
|
298
|
+
res.json({ domains, profiles: profileList, success: true });
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
LOG.error("Failed to list profiles: %s.", formatError(error));
|
|
302
|
+
res.status(500).json({ error: "Failed to list profiles: " + formatError(error), success: false });
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
// POST /config/profiles - Create or update a user-defined profile with domain mappings.
|
|
306
|
+
app.post("/config/profiles", async (req, res) => {
|
|
307
|
+
try {
|
|
308
|
+
const body = req.body;
|
|
309
|
+
const key = sanitizeString(body.key ?? "");
|
|
310
|
+
const profile = body.profile;
|
|
311
|
+
const domainMappings = body.domains;
|
|
312
|
+
// Validate key.
|
|
313
|
+
if (!key) {
|
|
314
|
+
res.status(400).json({ error: "Profile key is required.", success: false });
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
// Validate profile object.
|
|
318
|
+
if (!profile || (typeof profile !== "object")) {
|
|
319
|
+
res.status(400).json({ error: "Profile definition is required.", success: false });
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
// Sanitize string fields in the profile object, including nested channelSelection strings.
|
|
323
|
+
for (const [field, value] of Object.entries(profile)) {
|
|
324
|
+
if (typeof value === "string") {
|
|
325
|
+
profile[field] = sanitizeString(value);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (profile.channelSelection?.matchSelector) {
|
|
329
|
+
profile.channelSelection.matchSelector = sanitizeString(profile.channelSelection.matchSelector);
|
|
330
|
+
}
|
|
331
|
+
// Sanitize string fields in domain mappings if provided.
|
|
332
|
+
if (domainMappings) {
|
|
333
|
+
for (const [domain, config] of Object.entries(domainMappings)) {
|
|
334
|
+
for (const [field, value] of Object.entries(config)) {
|
|
335
|
+
if (typeof value === "string") {
|
|
336
|
+
config[field] = sanitizeString(value);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// Sanitize domain keys themselves. If the sanitized domain differs from the original, replace the entry.
|
|
340
|
+
const cleanDomain = sanitizeString(domain);
|
|
341
|
+
if (cleanDomain !== domain) {
|
|
342
|
+
domainMappings[cleanDomain] = config;
|
|
343
|
+
Reflect.deleteProperty(domainMappings, domain);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
// Check if this is a new profile or an update to an existing one.
|
|
348
|
+
const existingProfiles = getUserProfiles();
|
|
349
|
+
const isNew = !(key in existingProfiles);
|
|
350
|
+
// Validate the key format and built-in conflict.
|
|
351
|
+
const keyError = validateProfileKey(key, isNew);
|
|
352
|
+
if (keyError) {
|
|
353
|
+
res.status(400).json({ error: keyError, success: false });
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
// Validate the profile content: extends must reference a built-in profile, strategy must be recognized and generic, all flags must be valid SiteProfile fields.
|
|
357
|
+
const profileErrors = validateProfile(key, profile);
|
|
358
|
+
if (profileErrors.length > 0) {
|
|
359
|
+
res.status(400).json({ error: profileErrors.join(" "), success: false });
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
// Validate domain mappings if provided. Build the available profiles set from built-in + existing user profiles + the profile being saved.
|
|
363
|
+
if (domainMappings && (Object.keys(domainMappings).length > 0)) {
|
|
364
|
+
const availableProfiles = new Set(getProfiles().map((p) => p.name));
|
|
365
|
+
availableProfiles.add(key);
|
|
366
|
+
const domainErrors = [];
|
|
367
|
+
for (const [domain, config] of Object.entries(domainMappings)) {
|
|
368
|
+
domainErrors.push(...validateDomain(domain, config, availableProfiles));
|
|
369
|
+
}
|
|
370
|
+
if (domainErrors.length > 0) {
|
|
371
|
+
res.status(400).json({ error: domainErrors.join(" "), success: false });
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
// Save the profile and domain mappings. When updating an existing profile, remove stale domain mappings that pointed to this profile before applying the new
|
|
376
|
+
// ones. This handles the case where a user changes domain mappings on edit — without this cleanup, old domain entries would persist alongside the new ones.
|
|
377
|
+
const existingDomains = getUserDomains();
|
|
378
|
+
const mergedProfiles = { ...existingProfiles, [key]: profile };
|
|
379
|
+
const cleanedDomains = {};
|
|
380
|
+
for (const [domain, config] of Object.entries(existingDomains)) {
|
|
381
|
+
if (config.profile !== key) {
|
|
382
|
+
cleanedDomains[domain] = config;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
const mergedDomains = { ...cleanedDomains, ...(domainMappings ?? {}) };
|
|
386
|
+
await saveUserProfiles(mergedProfiles, mergedDomains);
|
|
387
|
+
const actionLabel = isNew ? "created" : "updated";
|
|
388
|
+
LOG.info("User profile '%s' %s.", key, actionLabel);
|
|
389
|
+
res.json({ key, message: "Profile '" + key + "' " + actionLabel + " successfully.", success: true });
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
LOG.error("Failed to save profile: %s.", formatError(error));
|
|
393
|
+
res.status(500).json({ error: "Failed to save profile: " + formatError(error), success: false });
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
// DELETE /config/profiles/:key - Delete a user-defined profile and its domain mappings.
|
|
397
|
+
app.delete("/config/profiles/:key", async (req, res) => {
|
|
398
|
+
try {
|
|
399
|
+
const key = req.params.key;
|
|
400
|
+
if (!key) {
|
|
401
|
+
res.status(400).json({ error: "Profile key is required.", success: false });
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
// Verify the profile exists as a user profile.
|
|
405
|
+
const userProfiles = getUserProfiles();
|
|
406
|
+
if (!(key in userProfiles)) {
|
|
407
|
+
res.status(404).json({ error: "Profile '" + key + "' not found.", success: false });
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
await deleteUserProfile(key);
|
|
411
|
+
res.json({ key, message: "Profile '" + key + "' deleted successfully.", success: true });
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
LOG.error("Failed to delete profile: %s.", formatError(error));
|
|
415
|
+
res.status(500).json({ error: "Failed to delete profile: " + formatError(error), success: false });
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
// POST /config/profiles/import - Import a provider pack. Accepts optional skipChannels flag in the request body.
|
|
419
|
+
app.post("/config/profiles/import", async (req, res) => {
|
|
420
|
+
try {
|
|
421
|
+
const rawData = req.body;
|
|
422
|
+
const skipChannels = rawData.skipChannels === true;
|
|
423
|
+
// Parse and validate the provider pack. The parseProviderPack function ignores unknown keys like skipChannels.
|
|
424
|
+
const parseResult = parseProviderPack(rawData);
|
|
425
|
+
if (!parseResult.pack) {
|
|
426
|
+
res.status(400).json({ error: "Validation errors:\n" + parseResult.errors.join("\n"), success: false });
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
// Import the validated pack. Profile/domain save failures are fatal; channel import failures are non-fatal warnings included in the response.
|
|
430
|
+
const importResult = await importProviderPack(parseResult.pack, { skipChannels });
|
|
431
|
+
if (!importResult.success) {
|
|
432
|
+
res.status(400).json({ error: "Import failed:\n" + importResult.errors.join("\n"), success: false });
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
const parts = [];
|
|
436
|
+
if (importResult.profilesAdded > 0) {
|
|
437
|
+
parts.push(String(importResult.profilesAdded) + " profile(s)");
|
|
438
|
+
}
|
|
439
|
+
if (importResult.domainsAdded > 0) {
|
|
440
|
+
parts.push(String(importResult.domainsAdded) + " domain mapping(s)");
|
|
441
|
+
}
|
|
442
|
+
if (importResult.channelsAdded > 0) {
|
|
443
|
+
parts.push(String(importResult.channelsAdded) + " channel(s)");
|
|
444
|
+
}
|
|
445
|
+
const summary = "Imported " + parts.join(", ") + " from '" + parseResult.pack.name + "'.";
|
|
446
|
+
LOG.info("%s", summary);
|
|
447
|
+
// Include any non-fatal warnings (e.g., channel import failures) so the client can report what succeeded and what didn't.
|
|
448
|
+
if (importResult.errors.length > 0) {
|
|
449
|
+
for (const warning of importResult.errors) {
|
|
450
|
+
LOG.warn("Import warning: %s", warning);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
res.json({ message: summary, success: true, summary: importResult, warnings: importResult.errors });
|
|
454
|
+
}
|
|
455
|
+
catch (error) {
|
|
456
|
+
LOG.error("Failed to import provider pack: %s.", formatError(error));
|
|
457
|
+
res.status(500).json({ error: "Failed to import provider pack: " + formatError(error), success: false });
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
// GET /config/profiles/export - Export one or more user profiles as a provider pack. Accepts comma-separated profile keys.
|
|
461
|
+
app.get("/config/profiles/export", (req, res) => {
|
|
462
|
+
try {
|
|
463
|
+
const profileParam = req.query.profile;
|
|
464
|
+
const includeDomains = req.query.domains !== "0";
|
|
465
|
+
const includeChannels = req.query.channels === "1";
|
|
466
|
+
const name = req.query.name;
|
|
467
|
+
if (!profileParam) {
|
|
468
|
+
res.status(400).json({ error: "Profile key is required (use ?profile=key).", success: false });
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
// Split comma-separated keys and trim whitespace.
|
|
472
|
+
const profileKeys = profileParam.split(",").map((k) => k.trim()).filter(Boolean);
|
|
473
|
+
if (profileKeys.length === 0) {
|
|
474
|
+
res.status(400).json({ error: "No valid profile keys provided.", success: false });
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
const pack = exportProviderPack(profileKeys, { includeChannels, includeDomains, name: name ?? profileKeys.join(", ") });
|
|
478
|
+
if (!pack) {
|
|
479
|
+
res.status(404).json({ error: "None of the requested profiles were found.", success: false });
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
// Use the first profile key for the filename when exporting multiple profiles.
|
|
483
|
+
const filename = (profileKeys.length === 1) ? profileKeys[0] : "prismcast";
|
|
484
|
+
res.setHeader("Content-Type", "application/json");
|
|
485
|
+
res.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "-provider-pack.json\"");
|
|
486
|
+
res.send(JSON.stringify(pack, null, 2) + "\n");
|
|
487
|
+
}
|
|
488
|
+
catch (error) {
|
|
489
|
+
LOG.error("Failed to export provider pack: %s.", formatError(error));
|
|
490
|
+
res.status(500).json({ error: "Failed to export provider pack: " + formatError(error), success: false });
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
// POST /config/profiles/test - Start a test flow by opening a URL with the user's profile applied.
|
|
494
|
+
app.post("/config/profiles/test", async (req, res) => {
|
|
495
|
+
try {
|
|
496
|
+
const { startLoginMode } = await import("../../browser/index.js");
|
|
497
|
+
const body = req.body;
|
|
498
|
+
const url = body.url?.trim();
|
|
499
|
+
if (!url) {
|
|
500
|
+
res.status(400).json({ error: "URL is required.", success: false });
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
// Validate URL format before opening the browser.
|
|
504
|
+
const urlError = validateChannelUrl(url);
|
|
505
|
+
if (urlError) {
|
|
506
|
+
res.status(400).json({ error: urlError, success: false });
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
const result = await startLoginMode(url);
|
|
510
|
+
if (!result.success) {
|
|
511
|
+
res.status(400).json({ error: result.error ?? "Failed to start test.", success: false });
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
res.json({ message: "Test page opened. The browser window should be visible.", success: true });
|
|
515
|
+
}
|
|
516
|
+
catch (error) {
|
|
517
|
+
LOG.error("Failed to start test flow: %s.", formatError(error));
|
|
518
|
+
res.status(500).json({ error: "Failed to start test: " + formatError(error), success: false });
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
// POST /config/profiles/test/check - Check CSS selectors against the live test page.
|
|
522
|
+
app.post("/config/profiles/test/check", async (req, res) => {
|
|
523
|
+
try {
|
|
524
|
+
const { getLoginPage } = await import("../../browser/index.js");
|
|
525
|
+
const body = req.body;
|
|
526
|
+
const selectors = body.selectors;
|
|
527
|
+
if (!selectors || (typeof selectors !== "object")) {
|
|
528
|
+
res.status(400).json({ error: "Selectors object is required.", success: false });
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
const page = getLoginPage();
|
|
532
|
+
if (!page) {
|
|
533
|
+
res.status(400).json({ error: "No active test page. Start a test first.", success: false });
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
// Evaluate all selectors in a single page.evaluate call to avoid await-in-loop.
|
|
537
|
+
const counts = await page.evaluate((selectorMap) => {
|
|
538
|
+
const output = {};
|
|
539
|
+
for (const [name, sel] of Object.entries(selectorMap)) {
|
|
540
|
+
try {
|
|
541
|
+
output[name] = document.querySelectorAll(sel).length;
|
|
542
|
+
}
|
|
543
|
+
catch {
|
|
544
|
+
output[name] = -1;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return output;
|
|
548
|
+
}, selectors);
|
|
549
|
+
const results = {};
|
|
550
|
+
for (const [name, count] of Object.entries(counts)) {
|
|
551
|
+
results[name] = { count: Math.max(count, 0), valid: count >= 0 };
|
|
552
|
+
}
|
|
553
|
+
res.json({ results, success: true });
|
|
554
|
+
}
|
|
555
|
+
catch (error) {
|
|
556
|
+
LOG.error("Failed to check selectors: %s.", formatError(error));
|
|
557
|
+
res.status(500).json({ error: "Failed to check selectors: " + formatError(error), success: false });
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
// POST /config/profiles/test/done - End an active test flow.
|
|
561
|
+
app.post("/config/profiles/test/done", async (_req, res) => {
|
|
562
|
+
try {
|
|
563
|
+
const { endLoginMode } = await import("../../browser/index.js");
|
|
564
|
+
await endLoginMode();
|
|
565
|
+
res.json({ message: "Test flow ended.", success: true });
|
|
566
|
+
}
|
|
567
|
+
catch (error) {
|
|
568
|
+
LOG.error("Failed to end test flow: %s.", formatError(error));
|
|
569
|
+
res.status(500).json({ error: "Failed to end test: " + formatError(error), success: false });
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
//# sourceMappingURL=providers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../../../src/routes/config/providers.ts"],"names":[],"mappings":"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"}
|