berlin_vbb.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // SPDX-FileCopyrightText: Adam Evyčędo
  2. //
  3. // SPDX-License-Identifier: AGPL-3.0-or-later
  4. package traffic
  5. import (
  6. "apiote.xyz/p/szczanieckiej/transformers"
  7. "bufio"
  8. "encoding/csv"
  9. "fmt"
  10. "io"
  11. "net/http"
  12. "os"
  13. "path/filepath"
  14. "strings"
  15. "time"
  16. "golang.org/x/text/transform"
  17. )
  18. type BerlinVbb struct {
  19. client http.Client
  20. }
  21. func (BerlinVbb) getTimezone() *time.Location {
  22. l, _ := time.LoadLocation("Europe/Berlin")
  23. return l
  24. }
  25. func (BerlinVbb) ConvertVehicles() ([]Vehicle, error) {
  26. return []Vehicle{}, nil
  27. }
  28. func (BerlinVbb) GetVersions(date time.Time, timezone *time.Location) ([]Version, error) {
  29. versions := []Version{}
  30. version, err := MakeVersionTimezone("00010101_99991231", timezone)
  31. if err != nil {
  32. return nil, err
  33. }
  34. version.Link = "https://www.vbb.de/fileadmin/user_upload/VBB/Dokumente/API-Datensaetze/gtfs-mastscharf/GTFS.zip"
  35. versions = append(versions, version)
  36. return versions, nil
  37. }
  38. func (BerlinVbb) String() string {
  39. return "berlin_vbb"
  40. }
  41. func (BerlinVbb) RealtimeFeeds() map[RealtimeFeedType]string {
  42. return map[RealtimeFeedType]string{}
  43. }
  44. func (BerlinVbb) Transformer() transform.Transformer {
  45. return transform.Chain(transformers.TransformerDE, transformers.TransformerPL, transformers.TransformerFR)
  46. }
  47. func (BerlinVbb) Name() string {
  48. return "Berlin/Brandenburg VBB"
  49. }
  50. func (BerlinVbb) Flags() FeedFlags {
  51. return FeedFlags{
  52. Headsign: HeadsignTripHeadsing,
  53. StopIdFormat: "{{stop_id}}_{{platform_code}}",
  54. StopName: "{{stop_name}} | {{platform_code}}", // TODO platform_code might not be present, but currently templating doesn’t support this
  55. LineName: "{{route_short_name}}",
  56. }
  57. }
  58. func (BerlinVbb) FeedPrepareZip(path string) error {
  59. // TODO remove or fix zones
  60. // NOTE add platform codes from stop_id
  61. stopsFile, err := os.Open(filepath.Join(path, "stops.txt"))
  62. if err != nil {
  63. return fmt.Errorf("while opening stops file: %w", err)
  64. }
  65. defer stopsFile.Close()
  66. stops2File, err := os.OpenFile(filepath.Join(path, "stops2.txt"), os.O_RDWR|os.O_CREATE, 0644)
  67. if err != nil {
  68. return fmt.Errorf("while opening stops2 file: %w", err)
  69. }
  70. defer stops2File.Close()
  71. r := csv.NewReader(bufio.NewReader(stopsFile))
  72. w := csv.NewWriter(stops2File)
  73. header, err := r.Read()
  74. if err != nil {
  75. return fmt.Errorf("while reading stops header: %w", err)
  76. }
  77. fields := map[string]int{}
  78. for i, headerField := range header {
  79. fields[headerField] = i
  80. }
  81. err = w.Write(header)
  82. if err != nil {
  83. return fmt.Errorf("while writing stops header: %w", err)
  84. }
  85. for {
  86. record, err := r.Read()
  87. if err == io.EOF {
  88. break
  89. }
  90. if err != nil {
  91. return fmt.Errorf("while reading a stop record: %w", err)
  92. }
  93. f, ok := fields["location_type"]
  94. if (!ok || record[f] == "" || record[f] == "0") && record[fields["platform_code"]] == "" {
  95. stopID := strings.Split(record[fields["stop_id"]], ":")
  96. if len(stopID) >= 5 {
  97. record[fields["platform_code"]] = stopID[4]
  98. }
  99. }
  100. err = w.Write(record)
  101. if err != nil {
  102. return fmt.Errorf("while writing a stop record: %w", err)
  103. }
  104. }
  105. w.Flush()
  106. err = os.Remove(filepath.Join(path, "stops.txt"))
  107. if err != nil {
  108. return fmt.Errorf("while removing stops: %w", err)
  109. }
  110. err = os.Rename(filepath.Join(path, "stops2.txt"), filepath.Join(path, "stops.txt"))
  111. if err != nil {
  112. return fmt.Errorf("while renaming stops: %w", err)
  113. }
  114. // NOTE fix route types
  115. routesFile, err := os.Open(filepath.Join(path, "routes.txt"))
  116. if err != nil {
  117. return fmt.Errorf("while opening routes file: %w", err)
  118. }
  119. defer routesFile.Close()
  120. routes2File, err := os.OpenFile(filepath.Join(path, "routes2.txt"), os.O_RDWR|os.O_CREATE, 0644)
  121. if err != nil {
  122. return fmt.Errorf("while opening routes2 file: %w", err)
  123. }
  124. defer routes2File.Close()
  125. r = csv.NewReader(bufio.NewReader(routesFile))
  126. w = csv.NewWriter(routes2File)
  127. header, err = r.Read()
  128. if err != nil {
  129. return fmt.Errorf("while reading routes header: %w", err)
  130. }
  131. fields = map[string]int{}
  132. for i, headerField := range header {
  133. fields[headerField] = i
  134. }
  135. err = w.Write(header)
  136. if err != nil {
  137. return fmt.Errorf("while writing routes header: %w", err)
  138. }
  139. for {
  140. record, err := r.Read()
  141. if err == io.EOF {
  142. break
  143. }
  144. if err != nil {
  145. return fmt.Errorf("while reading a route record: %w", err)
  146. }
  147. if record[fields["route_type"]] == "100" {
  148. record[fields["route_type"]] = "2"
  149. }
  150. if record[fields["route_type"]] == "109" {
  151. record[fields["route_type"]] = "1"
  152. }
  153. if record[fields["route_type"]] == "400" {
  154. record[fields["route_type"]] = "1"
  155. }
  156. if record[fields["route_type"]] == "700" {
  157. record[fields["route_type"]] = "3"
  158. }
  159. if record[fields["route_type"]] == "900" {
  160. record[fields["route_type"]] = "0"
  161. }
  162. if record[fields["route_type"]] == "1000" {
  163. record[fields["route_type"]] = "4"
  164. }
  165. err = w.Write(record)
  166. if err != nil {
  167. return fmt.Errorf("while writing a route record: %w", err)
  168. }
  169. }
  170. w.Flush()
  171. err = os.Remove(filepath.Join(path, "routes.txt"))
  172. if err != nil {
  173. return fmt.Errorf("while removing routes: %w", err)
  174. }
  175. err = os.Rename(filepath.Join(path, "routes2.txt"), filepath.Join(path, "routes.txt"))
  176. if err != nil {
  177. return fmt.Errorf("while renaming routes: %w", err)
  178. }
  179. return nil
  180. }
  181. func (BerlinVbb) QRInfo() (string, QRLocation, string) {
  182. return "qr.bvg.de", QRLocationPath, "/(?<SEL>.*)"
  183. }