fix(radio): canonicalize priority country aliases before querying

This commit is contained in:
Said Turksever committed 2026-11-03 14:50:23 +00:00
1 parent aff540ad39
commit 94e4c2176e
4 files changed
+36 -4

No files matched your search

+2 -1
View File
@@ -1,5 +1,6 @@
- Add optional keyless Radio priority-country coverage with up to 40 stations
per configured country inside the existing 750-station cap. Country query
per configured country inside the existing 750-station cap; the UK alias uses
the canonical GB code. Country query
failures do not block a healthy global catalog. Bound mirror attempts to three
and retry failed or partial refreshes after 60 seconds on all installations,
including those without priority countries configured (m3ayush, #1206).
+1
View File
@@ -6315,6 +6315,7 @@ play action; the source does not relay or record streams.
Optional `RADIO_PRIORITY_COUNTRIES` is a server-owned comma-separated list of
up to eight ISO alpha-2 codes (for example `IN,PL`). Restart after changing it.
The `UK` alias is canonicalized to `GB` before deduplication and querying.
It needs no API key and adds no POWER UP entry. An empty list preserves the
existing global/tag-based directory. Invalid configuration fails at startup.
+5 -3
View File
@@ -39,12 +39,14 @@ export function parseRadioPriorityCountries(value = '') {
const entries = Array.isArray(value) ? value : String(value).split(',');
const countries = [];
for (const entry of entries) {
const code = String(entry).trim().toUpperCase();
if (!code) continue;
if (!/^[A-Z]{2}$/.test(code) || !normalizeRadioCountryInput(code).valid)
const input = String(entry).trim().toUpperCase();
if (!input) continue;
const normalized = normalizeRadioCountryInput(input);
if (!/^[A-Z]{2}$/.test(input) || !normalized.valid)
throw new TypeError(
'RADIO_PRIORITY_COUNTRIES requires ISO alpha-2 country codes',
);
const code = normalized.code;
if (!countries.includes(code)) countries.push(code);
}
if (countries.length > PRIORITY_COUNTRY_LIMIT)
+28
View File
@@ -545,11 +545,39 @@ test('priority-country configuration is bounded, normalized and validated before
const { parseRadioPriorityCountries } = await import('../../server/providers/radio/catalog.js');
assert.deepEqual(parseRadioPriorityCountries(' in, PL,in, '), ['IN', 'PL']);
assert.deepEqual(parseRadioPriorityCountries(''), []);
assert.deepEqual(parseRadioPriorityCountries('uk,GB,UK'), ['GB']);
assert.deepEqual(parseRadioPriorityCountries('US,CA,IN,PL,DE,FR,UK,GB,JP'), ['US', 'CA', 'IN', 'PL', 'DE', 'FR', 'GB', 'JP']);
for (const value of ['ZZ', 'India', 'IN&limit=9999', 'US,CA,IN,PL,DE,FR,GB,JP,AU']) {
assert.throws(() => createProxy({ priorityCountries: value }), /RADIO_PRIORITY_COUNTRIES/);
}
});
test('UK aliases query and report GB once and retain British stations', async () => {
const countryQueries = [];
const middleware = createProxy({
priorityCountries: 'UK,GB',
fetchImpl: async (url) => {
const parsed = new URL(url);
if (parsed.pathname === '/json/servers')
return responseJson([{ name: 'de1.api.radio-browser.info' }]);
const country = parsed.searchParams.get('countrycode');
if (country) {
countryQueries.push(country);
return responseJson([station({ country: 'United Kingdom', countrycode: 'GB' })]);
}
return responseJson(healthyRowsForQuery(url));
},
});
const response = await invoke(middleware, '/stations');
assert.equal(response.status, 200);
const body = JSON.parse(response.body);
assert.deepEqual(countryQueries, ['GB']);
assert.deepEqual(body.coverage.priorityCountries, [
{ countryCode: 'GB', succeeded: true, stationCount: 1 },
]);
assert.equal(body.stations.find((row) => row.id === UUID)?.countryCode, 'GB');
});
test('low-click country stations survive a full global catalog, with bounded cached queries and deduplication', async () => {
const calls = [];
let active = 0;