From 3ce586243a49f34b36d0fe4099bbfb2631610f11 Mon Sep 17 00:00:00 2001 From: Ariel Costas Guerrero Date: Mon, 16 Mar 2026 13:01:36 +0100 Subject: New marquee generation logic for Xunta --- src/Enmarcha.Backend/Services/FeedService.cs | 27 +----- src/Enmarcha.Backend/Services/OtpService.cs | 8 +- .../Services/Processors/FeedConfigProcessor.cs | 2 +- .../Services/Processors/MarqueeProcessor.cs | 28 ------ .../Services/Processors/NextStopsProcessor.cs | 99 ++++++++++++++++++++-- 5 files changed, 101 insertions(+), 63 deletions(-) delete mode 100644 src/Enmarcha.Backend/Services/Processors/MarqueeProcessor.cs (limited to 'src/Enmarcha.Backend/Services') diff --git a/src/Enmarcha.Backend/Services/FeedService.cs b/src/Enmarcha.Backend/Services/FeedService.cs index c3e33fd..4ea3752 100644 --- a/src/Enmarcha.Backend/Services/FeedService.cs +++ b/src/Enmarcha.Backend/Services/FeedService.cs @@ -148,7 +148,7 @@ public class FeedService return result; } - public string NormalizeStopName(string feedId, string name) + public static string NormalizeStopName(string feedId, string name) { if (feedId == "vitrasa") { @@ -171,7 +171,7 @@ public class FeedService return Regex.Replace(normalized, @"[^a-z0-9]", ""); } - public string GetStreetName(string originalName) + public static string GetStreetName(string originalName) { var name = RemoveQuotationMarks.Replace(originalName, "").Trim(); var match = StreetNameRegex.Match(name); @@ -189,29 +189,6 @@ public class FeedService return streetName.Trim(); } - public string? GenerateMarquee(string feedId, List nextStops) - { - if (nextStops.Count == 0) return null; - - if (feedId is "vitrasa" or "tranvias" or "tussa" or "ourense") - { - var streets = nextStops - .Select(GetStreetName) - .Where(s => !string.IsNullOrWhiteSpace(s)) - .Distinct() - .ToList(); - - return string.Join(" - ", streets); - } - - return feedId switch - { - "xunta" => string.Join(" > ", nextStops), - "renfe" => string.Join(" - ", nextStops), - _ => string.Join(", ", nextStops.Take(4)) - }; - } - public bool IsStopHidden(string stopId) { return HiddenStops.Contains(stopId); diff --git a/src/Enmarcha.Backend/Services/OtpService.cs b/src/Enmarcha.Backend/Services/OtpService.cs index 0de06bf..8724cda 100644 --- a/src/Enmarcha.Backend/Services/OtpService.cs +++ b/src/Enmarcha.Backend/Services/OtpService.cs @@ -101,7 +101,7 @@ public class OtpService { Id = s.GtfsId, Code = _feedService.NormalizeStopCode(feedId, s.Code ?? string.Empty), - Name = _feedService.NormalizeStopName(feedId, s.Name), + Name = FeedService.NormalizeStopName(feedId, s.Name), Lat = s.Lat, Lon = s.Lon, ScheduledDepartures = pattern.TripsForDate @@ -180,7 +180,7 @@ public class OtpService var feedId = otpPlace.StopId?.Split(':')[0] ?? "unknown"; return new PlannerPlace { - Name = _feedService.NormalizeStopName(feedId, otpPlace.Name!), + Name = FeedService.NormalizeStopName(feedId, otpPlace.Name!), Lat = otpPlace.Lat, Lon = otpPlace.Lon, StopId = otpPlace.StopId, // Use string directly @@ -379,7 +379,7 @@ public class OtpService var feedId = pos.Stop?.GtfsId?.Split(':')[0] ?? "unknown"; return new PlannerPlace { - Name = _feedService.NormalizeStopName(feedId, pos.Name), + Name = FeedService.NormalizeStopName(feedId, pos.Name), Lat = pos.Latitude, Lon = pos.Longitude, StopId = pos.Stop?.GtfsId, @@ -393,7 +393,7 @@ public class OtpService var feedId = stop.GtfsId?.Split(':')[0] ?? "unknown"; return new PlannerPlace { - Name = _feedService.NormalizeStopName(feedId, stop.Name), + Name = FeedService.NormalizeStopName(feedId, stop.Name), Lat = stop.Latitude, Lon = stop.Longitude, StopId = stop.GtfsId, diff --git a/src/Enmarcha.Backend/Services/Processors/FeedConfigProcessor.cs b/src/Enmarcha.Backend/Services/Processors/FeedConfigProcessor.cs index 196091a..9fc46c7 100644 --- a/src/Enmarcha.Backend/Services/Processors/FeedConfigProcessor.cs +++ b/src/Enmarcha.Backend/Services/Processors/FeedConfigProcessor.cs @@ -20,7 +20,7 @@ public class FeedConfigProcessor : IArrivalsProcessor foreach (var arrival in context.Arrivals) { arrival.Route.ShortName = _feedService.NormalizeRouteShortName(feedId, arrival.Route.ShortName); - arrival.Headsign.Destination = _feedService.NormalizeStopName(feedId, arrival.Headsign.Destination); + arrival.Headsign.Destination = FeedService.NormalizeStopName(feedId, arrival.Headsign.Destination); // Apply Vitrasa-specific line formatting if (feedId == "vitrasa") diff --git a/src/Enmarcha.Backend/Services/Processors/MarqueeProcessor.cs b/src/Enmarcha.Backend/Services/Processors/MarqueeProcessor.cs deleted file mode 100644 index d5ff58e..0000000 --- a/src/Enmarcha.Backend/Services/Processors/MarqueeProcessor.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Enmarcha.Backend.Services.Processors; - -public class MarqueeProcessor : IArrivalsProcessor -{ - private readonly FeedService _feedService; - - public MarqueeProcessor(FeedService feedService) - { - _feedService = feedService; - } - - public Task ProcessAsync(ArrivalsContext context) - { - if (context.IsNano) return Task.CompletedTask; - - var feedId = context.StopId.Split(':')[0]; - - foreach (var arrival in context.Arrivals) - { - if (string.IsNullOrEmpty(arrival.Headsign.Marquee)) - { - arrival.Headsign.Marquee = _feedService.GenerateMarquee(feedId, arrival.NextStops); - } - } - - return Task.CompletedTask; - } -} diff --git a/src/Enmarcha.Backend/Services/Processors/NextStopsProcessor.cs b/src/Enmarcha.Backend/Services/Processors/NextStopsProcessor.cs index 5bdb5bb..84e0d0f 100644 --- a/src/Enmarcha.Backend/Services/Processors/NextStopsProcessor.cs +++ b/src/Enmarcha.Backend/Services/Processors/NextStopsProcessor.cs @@ -1,3 +1,4 @@ +using System.Text; using Enmarcha.Sources.OpenTripPlannerGql.Queries; namespace Enmarcha.Backend.Services.Processors; @@ -20,17 +21,105 @@ public class NextStopsProcessor : IArrivalsProcessor foreach (var arrival in context.Arrivals) { if (arrival.RawOtpTrip is not ArrivalsAtStopResponse.Arrival otpArrival) continue; + if (arrival.Headsign.Marquee is not null) continue; // Filter stoptimes that are after the current stop's departure var currentStopDeparture = otpArrival.ScheduledDepartureSeconds; - arrival.NextStops = otpArrival.Trip.Stoptimes - .Where(s => s.ScheduledDeparture > currentStopDeparture) - .OrderBy(s => s.ScheduledDeparture) - .Select(s => _feedService.NormalizeStopName(feedId, s.Stop.Name)) - .ToList(); + if (feedId == "xunta") + { + arrival.NextStops = otpArrival.Trip.Stoptimes + .Where(s => s.ScheduledDeparture > currentStopDeparture) + .OrderBy(s => s.ScheduledDeparture) + .Select(s => s.Stop.Description) + .Distinct() + .ToList(); + } + else + { + arrival.NextStops = otpArrival.Trip.Stoptimes + .Where(s => s.ScheduledDeparture > currentStopDeparture) + .OrderBy(s => s.ScheduledDeparture) + .Select(s => FeedService.NormalizeStopName(feedId, s.Stop.Name)) + .ToList(); + } + + arrival.Headsign.Marquee = GenerateMarquee(feedId, arrival.NextStops); } return Task.CompletedTask; } + + private static string? GenerateMarquee(string feedId, List nextStops) + { + if (nextStops.Count == 0) return null; + + if (feedId is "vitrasa" or "tranvias" or "tussa" or "ourense") + { + var streets = nextStops + .Select(FeedService.GetStreetName) + .Where(s => !string.IsNullOrWhiteSpace(s)) + .Distinct() + .ToList(); + + return string.Join(" - ", streets); + } + + if (feedId == "xunta") + { + var points = nextStops + .Select(SplitXuntaStopDescription) + .ToList(); + + List seenConcellos = new(); + List seenParroquias = new(); + List items = []; + + foreach (var (parroquia, concello) in points) + { + // Santiago de Compostela -- Santiago de Compostela > Conxo -- Santiago de Compostela > BiduĂ­do -- Ames > Calo -- Teo > Bugallido -- Ames + // Santiago de Compostela -> Conxo -> Bidueiro (Ames) -> Calo (Teo) -> Bugallido + string item = ""; + + if (!seenParroquias.Contains(parroquia)) + { + seenParroquias.Add(parroquia); + item += $"{parroquia}"; + + if (parroquia == concello) + { + seenConcellos.Add(concello); + } + + if (!seenConcellos.Contains(concello)) + { + seenConcellos.Add(concello); + item += $" ({concello})"; + } + + items.Add(item); + } + + } + + return string.Join(" > ", items); + } + + return feedId switch + { + "renfe" => string.Join(" - ", nextStops), + _ => string.Join(", ", nextStops.Take(4)) + }; + } + + private static (string parroquia, string concello) SplitXuntaStopDescription(string stopName) + { + var parts = stopName.Split(" -- ", 2); + if (parts.Length != 2) + { + return ("", ""); // TODO: Throw + } + + return (parts[0], parts[1]); + } } -- cgit v1.3