london_dft.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // SPDX-FileCopyrightText: Adam Evyčędo
  2. //
  3. // SPDX-License-Identifier: AGPL-3.0-or-later
  4. package traffic
  5. import (
  6. "bufio"
  7. "encoding/csv"
  8. "fmt"
  9. "io"
  10. "net/http"
  11. "os"
  12. "path/filepath"
  13. "strings"
  14. "time"
  15. "golang.org/x/text/transform"
  16. )
  17. type LondonDft struct {
  18. client http.Client
  19. }
  20. func (LondonDft) getTimezone() *time.Location {
  21. l, _ := time.LoadLocation("Europe/London")
  22. return l
  23. }
  24. func (g LondonDft) ConvertVehicles() ([]Vehicle, error) {
  25. return []Vehicle{}, nil
  26. }
  27. func (z LondonDft) GetVersions(_ time.Time, timezone *time.Location) ([]Version, error) {
  28. version, err := MakeVersionTimezone("00010101_99991231", timezone)
  29. version.Link = "https://data.bus-data.dft.gov.uk/timetable/download/gtfs-file/london/"
  30. return []Version{version}, err
  31. }
  32. func (LondonDft) String() string {
  33. return "london_dft"
  34. }
  35. func (LondonDft) RealtimeFeeds() map[RealtimeFeedType]string {
  36. return map[RealtimeFeedType]string{
  37. VEHICLE_POSITIONS: "https://data.bus-data.dft.gov.uk/avl/download/gtfsrt | zip gtfsrt.bin",
  38. }
  39. }
  40. func (LondonDft) Transformer() transform.Transformer {
  41. return transform.Nop
  42. }
  43. func (LondonDft) Name() string {
  44. return "London DfT"
  45. }
  46. func (LondonDft) Flags() FeedFlags {
  47. return FeedFlags{
  48. Headsign: HeadsignTripHeadsing,
  49. StopIdFormat: "{{stop_id}}",
  50. StopName: "{{stop_name}}",
  51. LineName: "{{route_short_name}}",
  52. }
  53. }
  54. func (LondonDft) FeedPrepareZip(path string) error {
  55. // NOTE fix routes
  56. routesFile, err := os.Open(filepath.Join(path, "routes.txt"))
  57. if err != nil {
  58. return fmt.Errorf("while opening routes file: %w", err)
  59. }
  60. defer routesFile.Close()
  61. routes2File, err := os.OpenFile(filepath.Join(path, "routes2.txt"), os.O_RDWR|os.O_CREATE, 0644)
  62. if err != nil {
  63. return fmt.Errorf("while opening routes2 file: %w", err)
  64. }
  65. defer routes2File.Close()
  66. r := csv.NewReader(bufio.NewReader(routesFile))
  67. w := csv.NewWriter(routes2File)
  68. header, err := r.Read()
  69. if err != nil {
  70. return fmt.Errorf("while reading routes header: %w", err)
  71. }
  72. fields := map[string]int{}
  73. for i, headerField := range header {
  74. fields[headerField] = i
  75. }
  76. if _, ok := fields["route_color"]; !ok {
  77. header = append(header, "route_color")
  78. }
  79. err = w.Write(header)
  80. if err != nil {
  81. return fmt.Errorf("while writing routes header: %w", err)
  82. }
  83. for {
  84. record, err := r.Read()
  85. if err == io.EOF {
  86. break
  87. }
  88. if err != nil {
  89. return fmt.Errorf("while reading a route record: %w", err)
  90. }
  91. // NOTE fix route types
  92. if record[fields["route_short_name"]] == "London Cable Car" {
  93. record[fields["route_type"]] = "6"
  94. }
  95. if record[fields["route_type"]] == "200" {
  96. record[fields["route_type"]] = "3"
  97. }
  98. // NOTE fix route colours
  99. colour := "ffffff"
  100. if record[fields["route_short_name"]] == "Bakerloo" {
  101. colour = "A45A2A"
  102. }
  103. if record[fields["route_short_name"]] == "Central" {
  104. colour = "DA291C"
  105. }
  106. if record[fields["route_short_name"]] == "Circle" {
  107. colour = "FFCD00"
  108. }
  109. if record[fields["route_short_name"]] == "District" {
  110. colour = "007A33"
  111. }
  112. if record[fields["route_short_name"]] == "Hammersmith & City" {
  113. colour = "E89CAE"
  114. }
  115. if record[fields["route_short_name"]] == "Jubilee" {
  116. colour = "7C878E"
  117. }
  118. if record[fields["route_short_name"]] == "Metropolitan" {
  119. colour = "840B55"
  120. }
  121. if record[fields["route_short_name"]] == "Northern" {
  122. colour = "000000"
  123. }
  124. if record[fields["route_short_name"]] == "Piccadilly" {
  125. colour = "10069F"
  126. }
  127. if record[fields["route_short_name"]] == "Victoria" {
  128. colour = "00A3E0"
  129. }
  130. if record[fields["route_short_name"]] == "Waterloo & City" {
  131. colour = "6ECEB2"
  132. }
  133. ix, ok := fields["route_color"]
  134. if !ok {
  135. record = append(record, colour)
  136. } else {
  137. record[ix] = colour
  138. }
  139. // NOTE fix underscore
  140. record[fields["route_short_name"]] = strings.ReplaceAll(record[fields["route_short_name"]], "_", " ")
  141. err = w.Write(record)
  142. if err != nil {
  143. return fmt.Errorf("while writing a route record: %w", err)
  144. }
  145. }
  146. w.Flush()
  147. err = os.Remove(filepath.Join(path, "routes.txt"))
  148. if err != nil {
  149. return fmt.Errorf("while removing routes: %w", err)
  150. }
  151. err = os.Rename(filepath.Join(path, "routes2.txt"), filepath.Join(path, "routes.txt"))
  152. if err != nil {
  153. return fmt.Errorf("while renaming routes: %w", err)
  154. }
  155. return nil
  156. }
  157. func (LondonDft) QRInfo() (string, QRLocation, string) {
  158. return "", QRLocationNone, ""
  159. }