poznan_ztm.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. package traffic
  2. import (
  3. "apiote.xyz/p/szczanieckiej/transformers"
  4. "encoding/csv"
  5. "fmt"
  6. "io"
  7. "net/http"
  8. "os"
  9. "path/filepath"
  10. "regexp"
  11. "strings"
  12. "time"
  13. "golang.org/x/text/language"
  14. "golang.org/x/text/transform"
  15. "git.sr.ht/~sircmpwn/go-bare"
  16. )
  17. type HtmlSelector struct {
  18. tag string
  19. id string
  20. class string
  21. }
  22. type ZtmPoznan struct {
  23. client http.Client
  24. }
  25. func (z ZtmPoznan) ConvertVehicles(path string) error {
  26. url := "https://ztm.poznan.pl/en/dla-deweloperow/getGtfsRtFile/?file=vehicle_dictionary.csv"
  27. response, err := z.client.Get(url)
  28. if err != nil {
  29. return fmt.Errorf("ConvertVehicles: cannot GET ‘%s’: %w", url, err)
  30. }
  31. result, err := os.Create(filepath.Join(path, "vehicles.bare"))
  32. if err != nil {
  33. return fmt.Errorf("ConvertVehicles: cannot create bare file: %w", err)
  34. }
  35. defer result.Close()
  36. r := csv.NewReader(response.Body)
  37. r.Comma = ','
  38. header, err := r.Read()
  39. if err != nil {
  40. fmt.Println("Header read error")
  41. return err
  42. }
  43. fields := map[string]int{}
  44. for i, headerField := range header {
  45. fields[headerField] = i
  46. }
  47. for {
  48. record, err := r.Read()
  49. if err == io.EOF {
  50. break
  51. }
  52. if err != nil {
  53. return err
  54. }
  55. var capabilites uint16 = 0
  56. if record[fields["ramp"]] == "1" {
  57. capabilites |= 0b0001
  58. }
  59. if record[fields["hf_lf_le"]] == "1" {
  60. capabilites |= 0b0010
  61. }
  62. if record[fields["hf_lf_le"]] == "2" {
  63. capabilites |= 0b0001_0000_0000
  64. }
  65. if record[fields["air_conditioner"]] == "1" {
  66. capabilites |= 0b0100
  67. }
  68. if record[fields["place_for_transp_bicycles"]] == "1" {
  69. capabilites |= 0b1000
  70. }
  71. if record[fields["voice_announcement_sys"]] == "1" {
  72. capabilites |= 0b0001_0000
  73. }
  74. if record[fields["ticket_machine"]] == "1" {
  75. capabilites |= 0b0010_0000
  76. }
  77. if record[fields["ticket_sales_by_the_driver"]] == "1" {
  78. capabilites |= 0b0100_0000
  79. }
  80. if record[fields["usb_charger"]] == "1" {
  81. capabilites |= 0b1000_0000
  82. }
  83. vehicle := Vehicle{
  84. Id: ID(record[0]),
  85. Capabilities: capabilites,
  86. }
  87. bytes, err := bare.Marshal(&vehicle)
  88. if err != nil {
  89. return err
  90. }
  91. _, err = result.Write(bytes)
  92. if err != nil {
  93. return err
  94. }
  95. }
  96. return nil
  97. }
  98. func (z ZtmPoznan) GetVersions(date time.Time) ([]Version, error) {
  99. url := "https://ztm.poznan.pl/en/dla-deweloperow/gtfsFiles"
  100. response, err := z.client.Get(url)
  101. if err != nil {
  102. return []Version{}, fmt.Errorf("GetVersions: cannot GET ‘%s’: %w", url, err)
  103. }
  104. doc, err := io.ReadAll(response.Body)
  105. if err != nil {
  106. return []Version{}, fmt.Errorf("GetVersions: cannot read whole html: %w", err)
  107. }
  108. regex, err := regexp.Compile("[0-9]{8}_[0-9]{8}\\.zip")
  109. versionStrings := regex.FindAllString(string(doc), -1)
  110. versionsSet := map[string]struct{}{}
  111. for _, v := range versionStrings {
  112. versionsSet[v] = struct{}{}
  113. }
  114. versions := []Version{}
  115. for v := range versionsSet {
  116. validityString := strings.Replace(v, ".zip", "", 1)
  117. version, err := MakeVersion(validityString, z.GetLocation())
  118. if err != nil {
  119. return nil, err
  120. }
  121. version.Link = "https://ztm.poznan.pl/en/dla-deweloperow/getGTFSFile/?file=" + v
  122. versions = append(versions, version)
  123. }
  124. return versions, nil
  125. }
  126. func (z ZtmPoznan) GetLocation() *time.Location {
  127. l, _ := time.LoadLocation("Europe/Warsaw")
  128. return l
  129. }
  130. func (z ZtmPoznan) String() string {
  131. return "poznan_ztm"
  132. }
  133. func (z ZtmPoznan) RealtimeFeeds() []string {
  134. return []string{"https://ztm.poznan.pl/en/dla-deweloperow/getGtfsRtFile/?file=feeds.pb"}
  135. }
  136. func (z ZtmPoznan) Transformer() transform.Transformer {
  137. return transformers.TransformerPL
  138. }
  139. func (z ZtmPoznan) Name() string {
  140. return "ZTM Poznań"
  141. }
  142. func (z ZtmPoznan) Attribution() map[language.Tag]string {
  143. return map[language.Tag]string{
  144. language.Und: "GTFS files downloaded from https://ztm.poznan.pl/pl/dla-deweloperow/gtfsFiles and converted to TRAFFIC",
  145. language.English: "GTFS files downloaded from https://ztm.poznan.pl/pl/dla-deweloperow/gtfsFiles and converted to TRAFFIC",
  146. language.Polish: "Pliki GTFS pobrane z https://ztm.poznan.pl/pl/dla-deweloperow/gtfsFiles i przekonwertowane do formatu TRAFFIC",
  147. }
  148. }
  149. func (z ZtmPoznan) Description() map[language.Tag]string {
  150. return map[language.Tag]string{
  151. language.Und: "Timetable for Poznań public transport organised by Zarząd Transportu Miejskiego (ZTM)",
  152. language.English: "Timetable for Poznań public transport organised by Zarząd Transportu Miejskiego (ZTM)",
  153. language.BritishEnglish: "Timetable for Poznań public transport organised by Zarząd Transportu Miejskiego (ZTM)",
  154. language.AmericanEnglish: "Timetable for Poznań public transport organized by Zarząd Transportu Miejskiego (ZTM)",
  155. language.Polish: "Rozkład jazdy poznańskiego transportu publicznego organizowanego przez Zarząd Transportu Miejskiego (ZTM)",
  156. }
  157. }