multiple urls per entry
Build and Push Docker Images / build-and-push (push) Successful in 27s

This commit is contained in:
Bram committed 2026-11-04 10:56:55 +01:00
1 parent 4bd2088edd
commit 608164dfdd
6 files changed
+155 -29

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "xtream-proxy",
"version": "2.0.0",
"version": "3.0.0",
"private": true,
"description": "Proxies the fastest available upstream from a list of Xtream Codes credentials",
"scripts": {
+45 -17
View File
@@ -20,37 +20,65 @@ function readConfigEntries() {
const entries = [];
data.forEach((item, index) => {
const label = `Config entry #${index + 1}`;
if (!item || typeof item !== 'object' || Array.isArray(item)) {
console.warn(`Config entry #${index + 1}: not an object, skipping`);
console.warn(`${label}: not an object, skipping`);
return;
}
const { url, username, password } = item;
if (typeof url !== 'string' || !url.trim()) {
console.warn(`Config entry #${index + 1}: missing url, skipping`);
if (item.url !== undefined) {
console.warn(`${label}: "url" is no longer supported and is ignored, use "urls"`);
}
const { urls, username, password } = item;
if (!Array.isArray(urls) || urls.length === 0) {
console.warn(`${label}: missing non-empty urls array, skipping`);
return;
}
if (typeof username !== 'string' || !username) {
console.warn(`Config entry #${index + 1}: missing username, skipping`);
console.warn(`${label}: missing username, skipping`);
return;
}
if (typeof password !== 'string' || !password) {
console.warn(`Config entry #${index + 1}: missing password, skipping`);
console.warn(`${label}: missing password, skipping`);
return;
}
let parsed;
try {
parsed = new URL(url);
} catch {
console.warn(`Config entry #${index + 1}: invalid url, skipping`);
return;
}
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
console.warn(`Config entry #${index + 1}: url must be http(s), skipping`);
const validUrls = [];
const seenUrls = new Set();
urls.forEach((rawUrl, urlIndex) => {
const urlLabel = `${label} url #${urlIndex + 1}`;
if (typeof rawUrl !== 'string' || !rawUrl.trim()) {
console.warn(`${urlLabel}: missing url, skipping`);
return;
}
const url = rawUrl.trim();
let parsed;
try {
parsed = new URL(url);
} catch {
console.warn(`${urlLabel}: invalid url, skipping`);
return;
}
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
console.warn(`${urlLabel}: url must be http(s), skipping`);
return;
}
if (seenUrls.has(url)) return;
seenUrls.add(url);
validUrls.push(url);
});
if (validUrls.length === 0) {
console.warn(`${label}: no valid urls, skipping`);
return;
}
entries.push({ url, username, password });
for (const url of validUrls) {
entries.push({ url, username, password });
}
});
return entries;
}
@@ -78,7 +106,7 @@ function reloadConfig() {
const removed = upstreams.filter((u) => !seen.has(u.key)).length;
const added = next.filter((u) => !previous.has(u.key)).length;
if (added || removed) {
console.log(`Config reloaded: ${next.length} upstream(s), +${added} / -${removed}`);
console.log(`Config reloaded: ${next.length} upstream URL(s), +${added} / -${removed}`);
}
upstreams = next;
+1 -1
View File
@@ -21,7 +21,7 @@ const settings = {
),
rejectUnauthorized: process.env.PROXY_INSECURE_TLS !== '1',
allowBusyFallback: process.env.ALLOW_BUSY_FALLBACK !== '0',
userAgent: process.env.USER_AGENT || 'xtream-proxy/2.0',
userAgent: process.env.USER_AGENT || 'xtream-proxy/3.0',
};
function validate() {
+1 -1
View File
@@ -70,7 +70,7 @@ function describeUpstream(upstream) {
function logProbeResults(snapshot) {
if (snapshot.length === 0) {
console.warn(`No upstreams configured in ${settings.configFile}`);
console.warn(`No upstream URLs configured in ${settings.configFile}`);
return;
}
+7 -9
View File
@@ -1,18 +1,16 @@
#
# Every entry must point to an Xtream-compatible panel that serves the same
# content. The proxy probes each entry via /player_api.php and picks the
# fastest one that is not at its connection limit.
#
# The URL may include a path prefix, e.g. https://example.com/portal
#
[
{
"url": "http://panel1.example.com:8080",
"urls": [
"http://panel1.example.com:8080",
"https://panel1.example.com"
],
"username": "user1",
"password": "pass1"
},
{
"url": "https://panel2.example.com",
"urls": [
"https://panel2.example.com"
],
"username": "user2",
"password": "pass2"
}