From 3573ecae94aa328591d4b3a6e2d05e4fc9e261fc Mon Sep 17 00:00:00 2001
From: Copilot <198982749+Copilot@users.noreply.github.com>
Date: Sat, 28 Feb 2026 23:32:50 +0100
Subject: Deduplicate and collapse routes with excessive short-name variants on
stop arrivals (#137)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: arielcostas <94913521+arielcostas@users.noreply.github.com>
---
src/Enmarcha.Backend/Services/FeedService.cs | 53 ++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
(limited to 'src/Enmarcha.Backend/Services/FeedService.cs')
diff --git a/src/Enmarcha.Backend/Services/FeedService.cs b/src/Enmarcha.Backend/Services/FeedService.cs
index 8b0d3e7..b7496ec 100644
--- a/src/Enmarcha.Backend/Services/FeedService.cs
+++ b/src/Enmarcha.Backend/Services/FeedService.cs
@@ -94,6 +94,59 @@ public class FeedService
return NormalizeRouteShortName(feedId, shortName);
}
+ ///
+ /// When 5 or more distinct routes share the same 3-character short-name prefix,
+ /// they are collapsed into a single entry showing "XG{prefix}" (xunta feed only).
+ ///
+ private const int RouteCollapseThreshold = 5;
+
+ ///
+ /// Deduplicates routes by (always). For the xunta feed only,
+ /// also collapses groups of or more routes that share the
+ /// same 3-character prefix into a single entry named "XG{prefix}" (e.g. "XG621").
+ /// Other feeds are returned deduplicated but otherwise unchanged.
+ ///
+ public List ConsolidateRoutes(string feedId, IEnumerable routes)
+ {
+ // Deduplicate by short name (case-insensitive)
+ var deduplicated = routes
+ .GroupBy(r => r.ShortName, StringComparer.OrdinalIgnoreCase)
+ .Select(g => g.First())
+ .ToList();
+
+ // Prefix collapsing only applies to xunta routes, which can have dozens of
+ // sub-routes per contract that would otherwise flood the badge list.
+ if (feedId != "xunta")
+ {
+ return deduplicated;
+ }
+
+ // Group by the first 3 characters; collapse groups meeting the threshold.
+ // When collapsing, the first entry's colour is used — routes in the same prefix
+ // group (e.g. all xunta "621.*" lines) share the same operator colour.
+ var result = new List();
+ foreach (var group in deduplicated.GroupBy(r => r.ShortName.Length >= 3 ? r.ShortName[..3] : r.ShortName))
+ {
+ var items = group.ToList();
+ if (items.Count >= RouteCollapseThreshold)
+ {
+ result.Add(new RouteInfo
+ {
+ GtfsId = items[0].GtfsId,
+ ShortName = $"XG{group.Key}",
+ Colour = items[0].Colour,
+ TextColour = items[0].TextColour
+ });
+ }
+ else
+ {
+ result.AddRange(items);
+ }
+ }
+
+ return result;
+ }
+
public string NormalizeStopName(string feedId, string name)
{
if (feedId == "vitrasa")
--
cgit v1.3