[vlc-commits] [Git][videolan/vlc][master] service discovery/radio: paginate station lists
Felix Paul Kühne (@fkuehne)
gitlab at videolan.org
Wed Jul 22 13:12:50 UTC 2026
Felix Paul Kühne pushed to branch master at VideoLAN / VLC
Commits:
7c7d50a4 by Felix Paul Kühne at 2026-07-22T14:23:20+02:00
service discovery/radio: paginate station lists
The Radio Browser API returns a default page of 1000 stations when no
limit is passed, so countries with more stations were silently truncated.
Fetch the station list in pages of 1000 using limit/offset and stop once
a short page is returned.
- - - - -
1 changed file:
- modules/services_discovery/radio.c
Changes:
=====================================
modules/services_discovery/radio.c
=====================================
@@ -36,6 +36,7 @@
#define DEFAULT_BASE_URL "https://all.api.radio-browser.info/" // Default Base URL for the Radio Browser API
#define MRL_PREFIX "radio://"
#define CSV_MAX_FIELDS 100
+#define STATIONS_PAGE_SIZE 1000
typedef struct
{
@@ -421,71 +422,89 @@ static int ReadDirectory(stream_t *p_access, input_item_node_t *p_node)
return VLC_EGENERIC;
}
- char *stations_endpoint;
- if (asprintf(&stations_endpoint, "%scsv/stations/bycountrycodeexact/%s?hidebroken=true&order=votes&reverse=true",
- p_sys->base_url, p_access->psz_location) < 0)
+ size_t offset = 0;
+ for (;;)
{
- return VLC_ENOMEM;
- }
+ char *stations_endpoint;
+ if (asprintf(&stations_endpoint,
+ "%scsv/stations/bycountrycodeexact/%s?hidebroken=true&order=votes&reverse=true&limit=%zu&offset=%zu",
+ p_sys->base_url, p_access->psz_location,
+ (size_t)STATIONS_PAGE_SIZE, offset) < 0)
+ {
+ return VLC_ENOMEM;
+ }
- csv_parser *parser = csv_parser_init(p_access, stations_endpoint, CSV_MAX_FIELDS);
- free(stations_endpoint);
+ csv_parser *parser = csv_parser_init(p_access, stations_endpoint, CSV_MAX_FIELDS);
+ free(stations_endpoint);
- if (!parser)
- {
- return VLC_EGENERIC;
- }
-
- int name_index = csv_parser_get_field_index(parser, "name");
- int url_index = csv_parser_get_field_index(parser, "url");
- int favicon_index = csv_parser_get_field_index(parser, "favicon");
- int homepage_index = csv_parser_get_field_index(parser, "homepage");
- int tags_index = csv_parser_get_field_index(parser, "tags");
- int language_index = csv_parser_get_field_index(parser, "language");
- int codec_index = csv_parser_get_field_index(parser, "codec");
- int bitrate_index = csv_parser_get_field_index(parser, "bitrate");
- if (name_index < 0 || url_index < 0)
- {
- msg_Err(p_access, "Missing required fields in station data");
- csv_parser_free(parser);
- return VLC_EGENERIC;
- }
-
- int ret;
- while ((ret = csv_parser_read_line(parser)))
- {
- if(vlc_killed())
- break;
- if (ret < 0)
+ if (!parser)
{
- continue;
+ return offset == 0 ? VLC_EGENERIC : VLC_SUCCESS;
}
- if (strlen(parser->fields[name_index]) == 0 || strlen(parser->fields[url_index]) == 0)
+ int name_index = csv_parser_get_field_index(parser, "name");
+ int url_index = csv_parser_get_field_index(parser, "url");
+ int favicon_index = csv_parser_get_field_index(parser, "favicon");
+ int homepage_index = csv_parser_get_field_index(parser, "homepage");
+ int tags_index = csv_parser_get_field_index(parser, "tags");
+ int language_index = csv_parser_get_field_index(parser, "language");
+ int codec_index = csv_parser_get_field_index(parser, "codec");
+ int bitrate_index = csv_parser_get_field_index(parser, "bitrate");
+ if (name_index < 0 || url_index < 0)
{
- continue;
+ msg_Err(p_access, "Missing required fields in station data");
+ csv_parser_free(parser);
+ return offset == 0 ? VLC_EGENERIC : VLC_SUCCESS;
}
- input_item_t *station_item = input_item_NewStream(parser->fields[url_index],
- parser->fields[name_index],
- INPUT_DURATION_INDEFINITE);
- if (!station_item)
+ size_t rows = 0;
+ bool killed = false;
+ int ret;
+ while ((ret = csv_parser_read_line(parser)))
{
- continue;
- }
+ if (vlc_killed())
+ {
+ killed = true;
+ break;
+ }
+ rows++;
+ if (ret < 0)
+ {
+ continue;
+ }
+
+ if (strlen(parser->fields[name_index]) == 0 || strlen(parser->fields[url_index]) == 0)
+ {
+ continue;
+ }
- SetMetaFromField(station_item, parser, favicon_index, vlc_meta_ArtworkURL);
- SetMetaFromField(station_item, parser, homepage_index, vlc_meta_URL);
- SetMetaFromField(station_item, parser, tags_index, vlc_meta_Genre);
- SetMetaFromField(station_item, parser, language_index, vlc_meta_Language);
+ input_item_t *station_item = input_item_NewStream(parser->fields[url_index],
+ parser->fields[name_index],
+ INPUT_DURATION_INDEFINITE);
+ if (!station_item)
+ {
+ continue;
+ }
+
+ SetMetaFromField(station_item, parser, favicon_index, vlc_meta_ArtworkURL);
+ SetMetaFromField(station_item, parser, homepage_index, vlc_meta_URL);
+ SetMetaFromField(station_item, parser, tags_index, vlc_meta_Genre);
+ SetMetaFromField(station_item, parser, language_index, vlc_meta_Language);
- SetMetaExtraFromField(station_item, parser, codec_index, "Codec");
- SetMetaExtraFromField(station_item, parser, bitrate_index, "Bitrate (kb/s)");
+ SetMetaExtraFromField(station_item, parser, codec_index, "Codec");
+ SetMetaExtraFromField(station_item, parser, bitrate_index, "Bitrate (kb/s)");
+
+ input_item_node_AppendItem(p_node, station_item);
+ input_item_Release(station_item);
+ }
+ csv_parser_free(parser);
- input_item_node_AppendItem(p_node, station_item);
- input_item_Release(station_item);
+ if (killed || rows < STATIONS_PAGE_SIZE)
+ {
+ break;
+ }
+ offset += rows;
}
- csv_parser_free(parser);
return VLC_SUCCESS;
}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/7c7d50a4f54051480e9d042909f02214d26889da
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/7c7d50a4f54051480e9d042909f02214d26889da
You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help
More information about the vlc-commits
mailing list