From 5e4b8b2214260a128c567ba7fe792c9ee99fb9ac Mon Sep 17 00:00:00 2001 From: josh Date: Mon, 16 Feb 2026 23:34:41 +1000 Subject: [PATCH] Logic updates --- NextFlight/Controller.fs | 64 +++++++++++++++++++++++++--------------- NextFlight/Program.fs | 2 +- NextFlight/Types.fs | 3 ++ 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/NextFlight/Controller.fs b/NextFlight/Controller.fs index f79a925..f211ddf 100644 --- a/NextFlight/Controller.fs +++ b/NextFlight/Controller.fs @@ -1,7 +1,6 @@ module Controller open System open System.Net.Http -open System.Text.RegularExpressions open NextFlight.Types open FSharp.Collections open HtmlAgilityPack @@ -36,7 +35,7 @@ let private formatDateReadable (date: DateTime) (timezone: string) = // Helper to extract city from "City / Airport" format let private extractCity (location: string) = match location.Split('/') with - | parts when parts.Length > 0 -> parts.[0].Trim() + | parts when parts.Length > 0 -> parts[0].Trim() | _ -> location let private calculateArrivalDate (departureDate: DateTime) (departureTime: string) (arrivalTime: string) = @@ -46,10 +45,10 @@ let private calculateArrivalDate (departureDate: DateTime) (departureTime: strin let arrParts = arrivalTime.Split(':') if depParts.Length = 2 && arrParts.Length = 2 then - let depHour = Int32.Parse(depParts.[0]) - let depMinute = Int32.Parse(depParts.[1]) - let arrHour = Int32.Parse(arrParts.[0]) - let arrMinute = Int32.Parse(arrParts.[1]) + let depHour = Int32.Parse(depParts[0]) + let depMinute = Int32.Parse(depParts[1]) + let arrHour = Int32.Parse(arrParts[0]) + let arrMinute = Int32.Parse(arrParts[1]) let depTimeOfDay = TimeSpan(depHour, depMinute, 0) let arrTimeOfDay = TimeSpan(arrHour, arrMinute, 0) @@ -67,8 +66,23 @@ let private calculateArrivalDate (departureDate: DateTime) (departureTime: strin // If any error in parsing, assume same day departureDate +let getLogoUrl rawFlight = $"https://content.airhex.com/content/logos/airlines_{rawFlight.AirlineCode}_60_60_t.png" + +let removeDuplicateWords (string: string) = + string.Split(' ') + |> Array.fold (fun acc word -> + match acc with + | [] -> [word] + | head :: _ when head = word -> acc + | _ -> word :: acc + ) [] + |> List.rev + |> String.concat " " + // Map RawFlight to Flight let private mapToFlight (raw: RawFlight) (timezone: string) : Flight = + + let arrivalDate = calculateArrivalDate raw.Date raw.DepartureTime raw.ArrivalTime { departureAirportCode = raw.FromCode @@ -80,8 +94,10 @@ let private mapToFlight (raw: RawFlight) (timezone: string) : Flight = arrivalDateReadable = formatDateReadable arrivalDate timezone arrivalTime = raw.ArrivalTime flightNumber = raw.FlightNumber + airlineCode = raw.AirlineCode airlineName = raw.Airline - aircraftType = raw.Aircraft + aircraftType = removeDuplicateWords raw.Aircraft + logoUrl = getLogoUrl raw } let private parseTableRow (row: HtmlNode) : RawFlight option = @@ -91,53 +107,54 @@ let private parseTableRow (row: HtmlNode) : RawFlight option = if cells = null || cells.Count < 13 then None else // Extract date - let dateNode = cells.[0].SelectSingleNode(".//span[@class='inner-date']") + let dateNode = cells[0].SelectSingleNode(".//span[@class='inner-date']") if dateNode = null then None else let dateStr = dateNode.InnerText.Trim() let date = DateTime.Parse(dateStr) // Flight number - let flightNumber = getInnerText (Some cells.[1]) + let flightNumber = getInnerText (Some cells[1]) // Registration - let registration = getInnerText (Some cells.[2]) + let registration = getInnerText (Some cells[2]) // From airport - let fromNode = cells.[3].SelectSingleNode(".//span[@class='tooltip']") + let fromNode = cells[3].SelectSingleNode(".//span[@class='tooltip']") let fromCode = getInnerText (Some fromNode) let fromFull = getAttributeValue (Some fromNode) "data-tooltip-value" // To airport - let toNode = cells.[4].SelectSingleNode(".//span[@class='tooltip']") + let toNode = cells[4].SelectSingleNode(".//span[@class='tooltip']") let toCode = getInnerText (Some toNode) let toFull = getAttributeValue (Some toNode) "data-tooltip-value" // Distance (remove commas) - let distanceStr = getInnerText (Some cells.[5]) + let distanceStr = getInnerText (Some cells[5]) let distance = if String.IsNullOrWhiteSpace(distanceStr) then 0 else Int32.Parse(distanceStr.Replace(",", "")) // Times - let depTime = getInnerText (Some cells.[6]) - let arrTime = getInnerText (Some cells.[7]) + let depTime = getInnerText (Some cells[6]) + let arrTime = getInnerText (Some cells[7]) // Airline - let airlineNode = cells.[8].SelectSingleNode(".//span[@class='tooltip']") + let airlineNode = cells[8].SelectSingleNode(".//span[@class='tooltip']") let airline = getAttributeValue (Some airlineNode) "data-tooltip-value" + let airlineCode = getInnerText (Some cells[8]) // Aircraft - let aircraftNode = cells.[9].SelectSingleNode(".//span[@class='tooltip']") + let aircraftNode = cells[9].SelectSingleNode(".//span[@class='tooltip']") let aircraft = getAttributeValue (Some aircraftNode) "data-tooltip-value" // Seat - look for pattern like "19A" in the seat cell - let seatText = cells.[10].InnerText + let seatText = cells[10].InnerText let seatMatch = System.Text.RegularExpressions.Regex.Match(seatText, @"\d+[A-Z]") let seat = if seatMatch.Success then seatMatch.Value else "" // Class and Reason from icons column - let iconsCell = cells.[12] + let iconsCell = cells[12] // Class let classNode = iconsCell.SelectSingleNode(".//span[contains(@class, 'class-')]") @@ -174,6 +191,7 @@ let private parseTableRow (row: HtmlNode) : RawFlight option = DepartureTime = depTime ArrivalTime = arrTime Airline = airline + AirlineCode = airlineCode Aircraft = aircraft Seat = seat Class = flightClass @@ -225,8 +243,8 @@ let GetNextFlights (username: string) (timezoneCountry: string) (timezoneCity: s try let timeParts = flight.DepartureTime.Split(':') if timeParts.Length = 2 then - let hour = Int32.Parse(timeParts.[0]) - let minute = Int32.Parse(timeParts.[1]) + let hour = Int32.Parse(timeParts[0]) + let minute = Int32.Parse(timeParts[1]) // Create departure DateTime in YOUR timezone let departureDateTime = DateTime(flight.Date.Year, flight.Date.Month, flight.Date.Day, hour, minute, 0) departureDateTime > now @@ -240,8 +258,8 @@ let GetNextFlights (username: string) (timezoneCountry: string) (timezoneCity: s try let timeParts = flight.DepartureTime.Split(':') if timeParts.Length = 2 then - let hour = Int32.Parse(timeParts.[0]) - let minute = Int32.Parse(timeParts.[1]) + let hour = Int32.Parse(timeParts[0]) + let minute = Int32.Parse(timeParts[1]) DateTime(flight.Date.Year, flight.Date.Month, flight.Date.Day, hour, minute, 0) else flight.Date diff --git a/NextFlight/Program.fs b/NextFlight/Program.fs index 7e2e87c..92f80dd 100644 --- a/NextFlight/Program.fs +++ b/NextFlight/Program.fs @@ -40,7 +40,7 @@ module Program = use_static (Path.Combine(AppContext.BaseDirectory, "wwwroot")) use_developer_exceptions service_config ServiceConfig - url "http://0.0.0.0:5001" + url "http://0.0.0.0:5000" } run app \ No newline at end of file diff --git a/NextFlight/Types.fs b/NextFlight/Types.fs index a3be485..2a67d51 100644 --- a/NextFlight/Types.fs +++ b/NextFlight/Types.fs @@ -13,6 +13,7 @@ type RawFlight = { DepartureTime: string ArrivalTime: string Airline: string + AirlineCode: string Aircraft: string Seat: string Class: string @@ -29,6 +30,8 @@ type Flight = { arrivalDateReadable: string arrivalTime: string flightNumber: string + airlineCode: string airlineName: string aircraftType: string + logoUrl: string } \ No newline at end of file