rubybikes 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +12 -0
  3. data/CONTRIBUTING.md +33 -0
  4. data/LICENSE +662 -0
  5. data/NOTICE +10 -0
  6. data/PROVIDERS.md +123 -0
  7. data/README.md +108 -0
  8. data/RELEASING.md +44 -0
  9. data/data/ATTRIBUTION.txt +290 -0
  10. data/data/geojson/ch_cantons.json +53 -0
  11. data/data/geojson/japan_prefectures.json +49 -0
  12. data/data/geojson/penang.json +63 -0
  13. data/data/graphql/charichari.graphql +12 -0
  14. data/data/graphql/ganxeta.graphql +22 -0
  15. data/data/graphql/otp.graphql +68 -0
  16. data/data/providers.json +1 -0
  17. data/data/pybikes/aksu.json +49 -0
  18. data/data/pybikes/ambici.json +166 -0
  19. data/data/pybikes/baksi.json +41 -0
  20. data/data/pybikes/batumvelo.json +19 -0
  21. data/data/pybikes/bcycle.json +326 -0
  22. data/data/pybikes/beryl.json +195 -0
  23. data/data/pybikes/bicicard.json +205 -0
  24. data/data/pybikes/bicicas.json +20 -0
  25. data/data/pybikes/bicielx.json +19 -0
  26. data/data/pybikes/biciferrolterra.json +21 -0
  27. data/data/pybikes/bicimad.json +16 -0
  28. data/data/pybikes/bicincitta.json +1551 -0
  29. data/data/pybikes/bicing.json +37 -0
  30. data/data/pybikes/bikeshare_ie.json +46 -0
  31. data/data/pybikes/bikeu.json +17 -0
  32. data/data/pybikes/bixi.json +21 -0
  33. data/data/pybikes/bizkaibizi.json +105 -0
  34. data/data/pybikes/careem.json +40 -0
  35. data/data/pybikes/charichari.json +106 -0
  36. data/data/pybikes/chartered_bike.json +86 -0
  37. data/data/pybikes/clujbike.json +17 -0
  38. data/data/pybikes/cyclocity.json +211 -0
  39. data/data/pybikes/cyclopolis.json +78 -0
  40. data/data/pybikes/cykleo.json +39 -0
  41. data/data/pybikes/decobike.json +18 -0
  42. data/data/pybikes/derp.json +114 -0
  43. data/data/pybikes/deutschebahn.json +97 -0
  44. data/data/pybikes/digitransit.json +123 -0
  45. data/data/pybikes/docomo.json +215 -0
  46. data/data/pybikes/easybike.json +160 -0
  47. data/data/pybikes/ecovelo.json +307 -0
  48. data/data/pybikes/emovity.json +17 -0
  49. data/data/pybikes/encicla.json +17 -0
  50. data/data/pybikes/fifteen.json +50 -0
  51. data/data/pybikes/fsm.json +16 -0
  52. data/data/pybikes/ganxeta.json +20 -0
  53. data/data/pybikes/gbfs.json +1578 -0
  54. data/data/pybikes/gira.json +20 -0
  55. data/data/pybikes/gyorbike.json +19 -0
  56. data/data/pybikes/hellocycling.json +248 -0
  57. data/data/pybikes/joco.json +22 -0
  58. data/data/pybikes/keolis.json +22 -0
  59. data/data/pybikes/kolumbus.json +18 -0
  60. data/data/pybikes/lastenvelo.json +30 -0
  61. data/data/pybikes/linkbike.json +17 -0
  62. data/data/pybikes/meiob.json +18 -0
  63. data/data/pybikes/mobhis.json +43 -0
  64. data/data/pybikes/movus.json +72 -0
  65. data/data/pybikes/nextbike.json +2443 -0
  66. data/data/pybikes/nextbike_gbfs.json +5 -0
  67. data/data/pybikes/nubija.json +18 -0
  68. data/data/pybikes/open_source_bike_share.json +28 -0
  69. data/data/pybikes/open_source_bike_share_v2.json +17 -0
  70. data/data/pybikes/openmove.json +20 -0
  71. data/data/pybikes/ov_fiets.json +20 -0
  72. data/data/pybikes/pedalada.json +66 -0
  73. data/data/pybikes/publibike.json +127 -0
  74. data/data/pybikes/qrobici.json +20 -0
  75. data/data/pybikes/roovee.json +245 -0
  76. data/data/pybikes/samba.json +52 -0
  77. data/data/pybikes/sejong.json +19 -0
  78. data/data/pybikes/seoulbike.json +18 -0
  79. data/data/pybikes/sharedmobility.json +63 -0
  80. data/data/pybikes/slovnaft_bajk.json +21 -0
  81. data/data/pybikes/smartbike.json +28 -0
  82. data/data/pybikes/smoove.json +26 -0
  83. data/data/pybikes/soltrafego.json +39 -0
  84. data/data/pybikes/tashu.json +20 -0
  85. data/data/pybikes/urbansharing.json +22 -0
  86. data/data/pybikes/velib.json +23 -0
  87. data/data/pybikes/velobike_kz.json +17 -0
  88. data/data/pybikes/velok.json +16 -0
  89. data/data/pybikes/veloway.json +20 -0
  90. data/data/pybikes/weelo.json +45 -0
  91. data/data/pybikes/wegoshare.json +141 -0
  92. data/data/pybikes/xian.json +19 -0
  93. data/data/pybikes/yelovelo.json +22 -0
  94. data/data/pybikes/youbike.json +173 -0
  95. data/data/upstream.json +7 -0
  96. data/lib/rubybikes/engine.rb +3 -0
  97. data/lib/rubybikes/native/authenticated.rb +95 -0
  98. data/lib/rubybikes/native/engine.rb +103 -0
  99. data/lib/rubybikes/native/gbfs.rb +169 -0
  100. data/lib/rubybikes/native/geometry.rb +53 -0
  101. data/lib/rubybikes/native/graphql.rb +135 -0
  102. data/lib/rubybikes/native/html_clients.rb +313 -0
  103. data/lib/rubybikes/native/json_providers.rb +174 -0
  104. data/lib/rubybikes/native/more_json.rb +126 -0
  105. data/lib/rubybikes/native/nextbike.rb +50 -0
  106. data/lib/rubybikes/native/provider.rb +84 -0
  107. data/lib/rubybikes/native/remaining_clients.rb +102 -0
  108. data/lib/rubybikes/native/response_cache.rb +78 -0
  109. data/lib/rubybikes/native/transport.rb +163 -0
  110. data/lib/rubybikes/native/xml_details.rb +159 -0
  111. data/lib/rubybikes/native.rb +30 -0
  112. data/lib/rubybikes/version.rb +5 -0
  113. data/lib/rubybikes.rb +201 -0
  114. data/sig/external.rbs +30 -0
  115. data/sig/manifest.yaml +8 -0
  116. data/sig/native.rbs +230 -0
  117. data/sig/rubybikes.rbs +143 -0
  118. metadata +230 -0
data/PROVIDERS.md ADDED
@@ -0,0 +1,123 @@
1
+ # Provider support and live status
2
+
3
+ Public checks recorded on **2026-11-04 and 2026-11-05 (UTC)**. RubyBikes implements the **85 concrete clients**
4
+ and preserves the **815 predefined networks** from PyBikes baseline
5
+ [`b8681d2344d2ccc61d7b99b089a8cdba167a169e`](https://github.com/eskerda/pybikes/commit/b8681d2344d2ccc61d7b99b089a8cdba167a169e).
6
+ The upstream snapshot and attribution are included in the gem's `data/` directory.
7
+
8
+ ## What provider coverage means
9
+
10
+ Release checks require a successful, nonempty offline fixture update from every
11
+ client, as well as construction of all predefined networks. Fixtures exercise
12
+ real native Ruby parsers, expected station/vehicle fields, and HTTP request
13
+ shapes; external HTTP is disabled in these tests. CI also enforces 95% Ruby line
14
+ coverage and reports branch coverage.
15
+
16
+ This is different from live availability. An operator may retire an endpoint,
17
+ put a website into maintenance, require credentials, or reject requests from a
18
+ particular network. The catalog retains these networks and their implementations
19
+ rather than silently dropping them or returning fabricated availability.
20
+
21
+ Four supported clients have no predefined networks in the baseline:
22
+ `NextbikeGbfs`, `KeolisIlevia`, `VCub`, and `OTP`. Use `build` with the client's
23
+ constructor parameters to configure them. Authenticated clients have fixture
24
+ coverage; their live status remains **requires credentials** unless tested with
25
+ operator-issued access. Public audits do not send placeholder credentials.
26
+
27
+ Discover the packaged catalog without contacting operators:
28
+
29
+ ```sh
30
+ bundle exec ruby -Ilib -rrubybikes -e 'RubyBikes.open { |b| puts b.providers.map { |p| [p["module"], p["class"], p["tags"].size].join("\t") } }'
31
+ ```
32
+
33
+ ## Verified public feed repairs
34
+
35
+ These changes preserve existing network tags and include offline regression
36
+ fixtures. Counts below are observations at the check time, not fixed expectations
37
+ for future operator responses.
38
+
39
+ | Network/client | Repair | Verified result |
40
+ | --- | --- | --- |
41
+ | `meiob` / Meiob | Parse padded decimal availability, including `08` and `09`, without Ruby's implicit octal interpretation. | 77 stations |
42
+ | `mibisivalencia` / Movus | Follow the official station page's map script to its JSON feed; accept spaced count labels and the accented `Actualizándose` state. Retain the older embedded marker format. | 30 stations |
43
+ | `bicisanvi` / Movus | Discover the current map script and its `/php/puntos.php` JSON endpoint using the same native implementation. | 14 stations |
44
+ | `publibike-aargau` / Publibike | Ignore null canton geometries before geographic filtering, matching the upstream behavior. Verified on 2026-11-05. | 68 stations |
45
+ | `publibike-bern` / Publibike | Apply the same null-geometry correction to both PubliBike and Velospot station formats. Verified on 2026-11-05. | 395 stations |
46
+ | `publibike-fribourg` / Publibike | Apply the same null-geometry correction. Verified on 2026-11-05. | 63 stations |
47
+
48
+ The native Samba implementation reads provider data with a restricted literal
49
+ parser. It accepts the published arrays, tuples, strings, and numeric values;
50
+ it does not evaluate scripts or execute provider-supplied expressions.
51
+
52
+ ## Selected successful live checks
53
+
54
+ These public, bounded probes successfully parsed nonempty native snapshots on
55
+ 2026-11-04. They are selected checks rather than a statement that every one of
56
+ the 815 catalog networks was available.
57
+
58
+ | Network | Client | Stations observed |
59
+ | --- | --- | ---: |
60
+ | `bicielx` | BiciElx | 114 |
61
+ | `bici-ferrol-terra` | BiciFerrolTerra | 18 |
62
+ | `girocleta` | Emovity | 36 |
63
+ | `passofundo` | Mobhis | 8 |
64
+ | `velobike` | VelobikeKZ | 152 |
65
+ | `bicicuenca` | Samba | 20 |
66
+
67
+ ## Known live access issues
68
+
69
+ The following observations were made on 2026-11-04 unless stated otherwise. They
70
+ do not disable fixture-tested clients or remove their
71
+ catalog entries. A timeout or HTTP denial describes the checking environment;
72
+ it is not proof that a service is permanently retired.
73
+
74
+ | Network | Public endpoint checked | Dated observation |
75
+ | --- | --- | --- |
76
+ | `gyorbike` | <https://www.gyorbike.hu/en/stations> | HTTP 200, but the operator serves “Karbantartás alatt / This page is under construction” with no station table or marker data. |
77
+ | `bikeu-bra` | <https://www.bra.org.pl/mapa-stacji.html> | Connection timed out at the five-second connection bound. No replacement feed was verified. |
78
+ | `bicicletar` | <https://www.bicicletar.com.br/mapaestacao.aspx> | HTTP 403. The baseline HTTP address and its HTTPS equivalent both rejected access. |
79
+ | `bikesantos` | <https://www.mobilicidade.com.br/bikesantos/mapaestacao.aspx> | HTTP 403 over HTTPS; no accessible replacement verified. |
80
+ | `bikevitoria` | <https://www.bikevitoria.com/mapaestacao.aspx> | HTTP 403; no accessible replacement verified. |
81
+ | Legacy EasyBike entries listed below | `http://reseller.easybike.gr/{city_uid}/api.php` | On 2026-11-05, HTTP 200 with `stations: null`: the endpoint publishes no station feed. No public replacement was verified. |
82
+
83
+ The affected legacy EasyBike entries are `athens-bikes`, `easybike-didymoteicho`,
84
+ `easybike-glyfada`, `easybike-igoumenitsa`, `easybike-ioannina`,
85
+ `easybike-karditsa`, `easybike-kinouria`, `easybike-komotini`, `easybike-patra`,
86
+ `easybike-rethymno`, and `easybike-samos`. The separate `easybike-mani` feed still
87
+ returned two stations in the same check. A null feed raises an explicit provider
88
+ error; a valid empty station array remains an empty snapshot.
89
+
90
+ Do not disable TLS verification or treat an HTML error/maintenance page as an
91
+ empty working bike network to make an audit pass. Preserve the previous snapshot
92
+ when an update fails.
93
+
94
+ ## Run a fresh public audit
95
+
96
+ Install the development dependencies, then audit a single network or the full
97
+ catalog:
98
+
99
+ ```sh
100
+ bundle install
101
+ bundle exec ruby bin/audit-providers --tag velib --timeout 15 --output /tmp/rubybikes-velib-status.json
102
+ bundle exec ruby bin/audit-providers --timeout 15 --output /tmp/rubybikes-provider-status.json
103
+ ```
104
+
105
+ The audit uses two workers, bounds connection/read time within each network's
106
+ update deadline, honors provider rate-limit cooldowns, and records UTC check
107
+ times, client names, statuses, and station/vehicle counts. It marks authenticated
108
+ entries `requires_credentials` rather than calling them with dummy keys. Output
109
+ statuses include `working`, `empty`, `timeout`, `rate_limited`, `error`, and
110
+ `requires_credentials`. Error reports exclude provider response bodies and
111
+ credential-bearing URLs.
112
+
113
+ The **Audit public provider feeds** GitHub Actions workflow provides the same
114
+ manual check. Supply a network tag for a targeted probe, or leave it empty for
115
+ all predefined networks; download the `provider-status` artifact afterward.
116
+ The JSON report is written incrementally and includes a `complete` flag; partial
117
+ results remain available if an audit is interrupted. Live audits are deliberately separate from pull-request and release test gates,
118
+ so an operator outage does not make deterministic fixture tests fail.
119
+
120
+ When repairing a changed feed, keep its existing tag, verify the operator's
121
+ published endpoint, add a sanitized response fixture and explicit expected
122
+ fields, and record the dated live result. Never commit provider credentials or
123
+ RubyGems recovery codes.
data/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # RubyBikes
2
+
3
+ Native Ruby clients for bike-sharing stations and free-floating vehicles. The
4
+ catalog contains **815 networks in 53 countries**, backed by **85 provider
5
+ clients** adapted from [PyBikes](https://github.com/eskerda/pybikes). Operators are
6
+ queried directly; no CityBikes API service or Python installation is required.
7
+
8
+ Requires Ruby **3.1 or newer**. Install with `gem install rubybikes`, or add
9
+ `gem 'rubybikes'` to your application's Gemfile.
10
+
11
+ ```ruby
12
+ require 'rubybikes'
13
+
14
+ RubyBikes.open do |bikes|
15
+ network = bikes.get('velib')
16
+ network.update
17
+ network.stations.each do |station|
18
+ puts [station.id, station.name, station.bikes, station.free].inspect
19
+ end
20
+ puts network.to_json
21
+ end
22
+ ```
23
+
24
+ `get('velib')`, `get(tag: 'velib')`, and the original `get('tag' => 'velib')`
25
+ are equivalent. `get(label: 'Gbfs')` returns matching networks. `tags`, `labels`,
26
+ `catalog`, and `providers` provide discovery without contacting operators.
27
+ Provider records include module/class names, tags, and `authed`, `sync`, and
28
+ `unifeed` flags. Each system exposes `provider` and `client_class`.
29
+
30
+ ```ruby
31
+ RubyBikes.open do |bikes|
32
+ system = bikes.build(
33
+ provider: 'NextbikeGbfs', tag: 'custom-ambici', domain: 'bs',
34
+ meta: { name: 'Ambici', city: 'Barcelona', country: 'ES' }
35
+ )
36
+ system.update
37
+ end
38
+ ```
39
+
40
+ Custom definitions accept upstream constructor parameter names. Class names take
41
+ precedence over module names, case-insensitively. Specify `class_name:` for a
42
+ module with multiple clients, for example `provider: 'keolis', class_name: 'VCub'`.
43
+ All 85 clients are supported, including the four without predefined networks:
44
+ `NextbikeGbfs`, `KeolisIlevia`, `VCub`, and `OTP`.
45
+
46
+ Stations expose `id` (`get_hash`), `name`, `latitude`, `longitude`, `bikes`,
47
+ `free`, UTC `timestamp`, and provider-specific `extra`. Unknown counts remain
48
+ `nil`. Vehicles expose coordinates, `kind`, identity, timestamp, and `extra`.
49
+ Systems, stations, and vehicles support `to_h`/`to_dict`, `to_json`, and
50
+ `to_geojson`. Station IDs retain the PyBikes coordinate-based MD5 convention;
51
+ vehicle IDs retain their network and vehicle identity components.
52
+
53
+ Authenticated clients accept `api_key:` in `get` or `build`. Alternatively,
54
+ configure `RubyBikes.new(keys: { provider_module => credentials })`; tag and
55
+ class-name keys are also accepted. Resolution prefers an explicit key, then a
56
+ network-tag key, provider-module key, and finally a client-class key. Structured keys
57
+ retain the upstream field names, such as BiciMAD `clientid`/`passkey` and Weelo
58
+ `client_id`/`client_secret`. Never commit provider credentials.
59
+
60
+ Updates have a default 60-second overall deadline; use `RubyBikes.new(timeout:
61
+ 45)` or `system.update(timeout: 30)` to override it. Individual connections and
62
+ reads are bounded to 5 and 20 seconds and share the update deadline. TLS is
63
+ verified, HTTP redirects are bounded, cookies are scoped, and rate limits raise
64
+ `RubyBikes::RateLimitedError` with `host` and `retry_after`. Authentication refresh
65
+ is supported; failed provider requests are not automatically retried. Failed
66
+ updates retain the previous complete Ruby snapshot. A factory serializes its
67
+ updates; use separate factories for concurrent networks.
68
+
69
+ Errors use `RubyBikes::ProviderError`, `TimeoutError`, `ProtocolError`,
70
+ `NoSystemFoundError`, `NoGetCriteriaError`, and `APIKeyNotAvailableError`.
71
+ Provider response bodies and credential-bearing URLs are excluded from error
72
+ messages. Original top-level exception aliases remain available.
73
+
74
+ ## Development
75
+
76
+ ```sh
77
+ bin/setup
78
+ bundle exec rake test build
79
+ ruby .github/scripts/package_smoke.rb
80
+ ```
81
+
82
+ Tests use Minitest, WebMock, and checked-in response fixtures; external requests
83
+ are disabled. CI requires a successful nonempty fixture update from every client,
84
+ constructs all 815 catalog networks, and enforces 95% line coverage with branch
85
+ coverage reported. Type definitions ship in `sig/`.
86
+
87
+ Quality tooling uses Ruby 3.4 and a separate bundle so runtime compatibility can
88
+ remain Ruby 3.1+:
89
+
90
+ ```sh
91
+ BUNDLE_GEMFILE=gemfiles/quality.gemfile bundle install
92
+ BUNDLE_GEMFILE=gemfiles/quality.gemfile bundle exec rake lint typecheck
93
+ ```
94
+
95
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for provider changes,
96
+ [PROVIDERS.md](PROVIDERS.md) for live status and known issues, and
97
+ [RELEASING.md](RELEASING.md) for publishing.
98
+
99
+ ## Migrating from 0.2
100
+
101
+ The Python subprocess and its requirements have been removed. Delete any
102
+ `python:` constructor argument and `RUBYBIKES_PYTHON` configuration. `engine_info`
103
+ now reports `implementation: 'ruby'`, the gem version, and the upstream baseline
104
+ revision. `close` and the block form remain supported; no child process is used.
105
+ The old direct-require adapter files were retired; use the RubyBikes factory.
106
+
107
+ Distributed under AGPL-3.0. See [LICENSE](LICENSE), [NOTICE](NOTICE), and the
108
+ preserved upstream attribution in `data/ATTRIBUTION.txt`.
data/RELEASING.md ADDED
@@ -0,0 +1,44 @@
1
+ # Releasing RubyBikes
2
+
3
+ Publishing uses the `release.yml` workflow in `edumucelli/rubybikes`, environment
4
+ `release`, and immutable RubyGems owner **255571**. Configure a pending trusted
5
+ publisher under that RubyGems account for the first release, or an existing-gem
6
+ trusted publisher for later releases. Enable MFA on the RubyGems account.
7
+
8
+ The pending publisher described during setup expires after about twelve hours.
9
+ If it expires before the first release, recreate it before publishing. Do not
10
+ release incomplete code merely to use an expiring publisher.
11
+
12
+ The public RubyGems action versions inspected during development do not expose
13
+ an owner input. `.github/scripts/configure_rubygems.rb` performs the documented
14
+ OIDC exchange directly, sending `{jwt: ..., owner: "255571"}`. RubyGems requires
15
+ the owner ID to be a string. It masks the
16
+ short-lived API key and passes it through the temporary Actions environment
17
+ file. No long-lived API key is stored in repository secrets or a credentials
18
+ file. A future migration to an official action must verify that the action
19
+ actually forwards the owner input, especially for the first push.
20
+
21
+ 1. Bump `RubyBikes::VERSION` in `lib/rubybikes/version.rb` and update the
22
+ changelog, then push or merge the commit into `master` on GitHub.
23
+ 2. The release workflow runs native tests, all-client fixture verification,
24
+ 95% coverage, lint, type checks, and the installed-package smoke test.
25
+ 3. After CI passes, the workflow reads the version from that file and checks
26
+ RubyGems. Already published versions are skipped; registry errors fail the
27
+ release instead of treating the version as available.
28
+ 4. For an unpublished version, it verifies master ancestry, builds and checks
29
+ the package, exchanges OIDC credentials for owner **255571**, and publishes
30
+ to RubyGems. It then creates the matching tag (for example `v0.3.0`) at the
31
+ tested commit and a GitHub release with the gem attached. An existing tag
32
+ pointing to a different commit blocks publication.
33
+
34
+ No manual tag is needed. Changes to `release.yml` or its credential/version
35
+ scripts also trigger the workflow, allowing the initial `0.3.0` release without
36
+ a redundant version bump. To retry
37
+ an unpublished version after fixing a release problem, run `release.yml`
38
+ manually with `workflow_dispatch` on `master`.
39
+
40
+ A failed validation or failed CI run cannot publish. A RubyGems push failure
41
+ prevents GitHub release creation. If publication succeeded but GitHub release
42
+ creation failed, create the release at the published commit without republishing
43
+ or overwriting the gem. RubyGems versions are immutable; rerunning the workflow
44
+ skips a version that is already on RubyGems.
@@ -0,0 +1,290 @@
1
+ aksu.py
2
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
3
+ # Distributed under the AGPL license, see LICENSE.txt
4
+
5
+ ambici.py
6
+ # Copyright (C) 2010-2023, eskerda <eskerda@gmail.com>
7
+ # Distributed under the AGPL license, see LICENSE.txt
8
+
9
+ baksi.py
10
+ # Copyright (C) 2010-2012, eskerda <eskerda@gmail.com>
11
+ # Distributed under the AGPL license, see LICENSE.txt
12
+
13
+ base.py
14
+ # Copyright (C) 2010-2025, eskerda <eskerda@gmail.com>
15
+ # Distributed under the AGPL license, see LICENSE.txt
16
+
17
+ batumvelo.py
18
+ # Copyright (C) 2025, Martín González Gómez <m@martingonzalez.net>
19
+ # Copyright (C) 2026, eskerda <eskerda@gmail.com>
20
+ # Distributed under the AGPL license, see LICENSE.txt
21
+
22
+ bcycle.py
23
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
24
+ # Distributed under the AGPL license, see LICENSE.txt
25
+
26
+ beryl.py
27
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
28
+ # Distributed under the AGPL license, see LICENSE.txt
29
+
30
+ bicicard.py
31
+ # Copyright (C) 2023, eskerda <eskerda@gmail.com>
32
+ # Distributed under the AGPL license, see LICENSE.txt
33
+
34
+ bicicas.py
35
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
36
+ # Distributed under the AGPL license, see LICENSE.txt
37
+
38
+ bicielx.py
39
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
40
+ # Distributed under the AGPL license, see LICENSE.txt
41
+
42
+ biciferrolterra.py
43
+ # Copyright (C) 2024, Martín González Gómez <m@martingonzalez.net>
44
+ # Distributed under the AGPL license, see LICENSE.txt
45
+
46
+ bicimad.py
47
+ # Copyright (C) 2018, eskerda <eskerda@gmail.com>
48
+ # Copyright (C) 2021, Altonss (https://github.com/Altonss)
49
+ # Copyright (C) 2022, eUgEntOptIc44 (https://github.com/eUgEntOptIc44)
50
+ # Distributed under the AGPL license, see LICENSE.txt
51
+
52
+ bicincitta.py
53
+ # Copyright (C) 2019, eskerda <eskerda@gmail.com>
54
+ # Distributed under the AGPL license, see LICENSE.txt
55
+
56
+ bikeshare_ie.py
57
+ # Copyright (C) 2025, Martín González Gómez <m@martingonzalez.net>
58
+ # Copyright (C) Eduardo Mucelli Rezende Oliveira <edumucelli@gmail.com>
59
+ # Distributed under the AGPL license, see LICENSE.txt
60
+
61
+ bikeu.py
62
+ # Copyright (C) 2015, thesebas <thesebas@thesebas.net>
63
+ # Distributed under the AGPL license, see LICENSE.txt
64
+
65
+ bixi.py
66
+ # Copyright (C) 2010-2012, eskerda <eskerda@gmail.com>
67
+ # Distributed under the AGPL license, see LICENSE.txt
68
+
69
+ bizkaibizi.py
70
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
71
+ # Distributed under the AGPL license, see LICENSE.txt
72
+
73
+ careem.py
74
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
75
+ # Distributed under the AGPL license, see LICENSE.txt
76
+
77
+ charichari.py
78
+ # Copyright (C) 2026, Martín González Gómez <m@martingonzalez.net>
79
+
80
+ clujbike.py
81
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
82
+ # Distributed under the AGPL license, see LICENSE.txt
83
+
84
+ cyclocity.py
85
+ # Copyright (C) 2010-2026, eskerda <eskerda@gmail.com>
86
+ # Distributed under the AGPL license, see LICENSE.txt
87
+
88
+ cyclopolis.py
89
+ # Copyright (C) 2015, Eduardo Mucelli Rezende Oliveira <edumucelli@gmail.com>
90
+ # Copyright (C) 2025, Martín González Gómez <m@martingonzalez.net.com>
91
+ # Distributed under the AGPL license, see LICENSE.txt
92
+
93
+ cykleo.py
94
+ # Copyright (C) 2010-2023, eskerda <eskerda@gmail.com>
95
+ # Distributed under the AGPL license, see LICENSE.txt
96
+
97
+ decobike.py
98
+ # Copyright (C) 2010-2023, eskerda <eskerda@gmail.com>
99
+ # Distributed under the AGPL license, see LICENSE.txt
100
+
101
+ deutschebahn.py
102
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
103
+ # Copyright (C) 2023, Lluis Esquerda <eskerda@gmail.com>
104
+ # Distributed under the AGPL license, see LICENSE.txt
105
+
106
+ docomo.py
107
+ # Copyright (C) 2024, Martín González Gómez <m@martingonzalez.net>
108
+ # Distributed under the AGPL license, see LICENSE.txt
109
+
110
+ easybike.py
111
+ # Copyright (C) 2015, bparmentier <dev@brunoparmentier.be>
112
+ # Copyright (C) 2016, Eduardo Mucelli Rezende Oliveira <edumucelli@gmail.com>
113
+ # Copyright (C) 2016, eskerda <eskerda@gmail.com>
114
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
115
+ # Distributed under the AGPL license, see LICENSE.txt
116
+
117
+ ecovelo.py
118
+ # Copyright (C) 2021, Altonss https://github.com/Altonss
119
+ # Distributed under the AGPL license, see LICENSE.txt
120
+
121
+ emovity.py
122
+ # Copyright (C) 2010-2021, eskerda <eskerda@gmail.com>
123
+ # Distributed under the AGPL license, see LICENSE.txt
124
+
125
+ encicla.py
126
+ # Copyright (C) 2015, Eduardo Mucelli Rezende Oliveira <edumucelli@gmail.com>
127
+ # Copyright (C) 2023, eskerda <eskerda@gmail.com>
128
+ # Distributed under the AGPL license, see LICENSE.txt
129
+
130
+ fsm.py
131
+ # Copyright (C) 2017, aronsky <aronsky@gmail.com>
132
+ # Copyright (C) 2023, eskerda <eskerda@gmail.com>
133
+
134
+ ganxeta.py
135
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
136
+
137
+ gbfs.py
138
+ # Copyright (C) 2010-2012, eskerda <eskerda@gmail.com>
139
+ # Distributed under the AGPL license, see LICENSE.txt
140
+
141
+ gira.py
142
+ # Copyright (C) 2010-2023, eskerda <eskerda@gmail.com>
143
+ # Distributed under the AGPL license, see LICENSE.txt
144
+
145
+ gyorbike.py
146
+ # Copyright (C) 2026, Martín González Gómez <m@martingonzalez.net>
147
+ # Copyright (C) 2026, eskerda <eskerda@gmail.com>
148
+ # Distributed under the AGPL license, see LICENSE.txt
149
+
150
+ hellocycling.py
151
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
152
+ # Distributed under the AGPL license, see LICENSE.txt
153
+
154
+ joco.py
155
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
156
+
157
+ keolis.py
158
+ # Copyright (C) 2010-2012, eskerda <eskerda@gmail.com>
159
+ # Distributed under the AGPL license, see LICENSE.txt
160
+
161
+ kolumbus.py
162
+ # Copyright (C) 2024, eskerda <eskerda@gmail.com>
163
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
164
+ # Distributed under the AGPL license, see LICENSE.txt
165
+
166
+ lastenvelo.py
167
+ # Copyright (C) 2024, eskerda <eskerda@gmail.com>
168
+ # Distributed under the AGPL license, see LICENSE.txt
169
+
170
+ linkbike.py
171
+ # Copyright (C) 2024, Martín González Gómez <m@martingonzalez.net>
172
+ # Distributed under the AGPL license, see LICENSE.txt
173
+
174
+ meiob.py
175
+ # Copyright (C) 2024, Martín González Gómez <m@martingonzalez.net>
176
+ # Distributed under the AGPL license, see LICENSE.txt
177
+
178
+ mobhis.py
179
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
180
+ # Distributed under the AGPL license, see LICENSE.txt
181
+
182
+ movus.py
183
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
184
+ # Copyright (C) 2023, Lluis Esquerda <eskerda@gmail.com>
185
+ # Distributed under the AGPL license, see LICENSE.txt
186
+
187
+ nextbike.py
188
+ # Copyright (C) 2010-2012, eskerda <eskerda@gmail.com>
189
+ # Distributed under the AGPL license, see LICENSE.txt
190
+
191
+ nextbike_gbfs.py
192
+ # Copyright (C) 2025, eskerda <eskerda@gmail.com>
193
+ # Distributed under the AGPL license, see LICENSE.txt
194
+
195
+ nubija.py
196
+ # Copyright (C) 2024, Martín González Gómez <m@martingonzalez.net>
197
+ # Copyright (C) 2025, eskerda <eskerda@gmail.com>
198
+ # Distributed under the AGPL license, see LICENSE.txt
199
+
200
+ open_source_bike_share.py
201
+ # Copyright (C) Eduardo Mucelli Rezende Oliveira <edumucelli@gmail.com>
202
+ # Distributed under the AGPL license, see LICENSE.txt
203
+
204
+ open_source_bike_share_v2.py
205
+ # Distributed under the AGPL license, see LICENSE.txt
206
+
207
+ openmove.py
208
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
209
+
210
+ ov_fiets.py
211
+ # Copyright (C) 2024, eskerda <eskerda@gmail.com>
212
+ # Distributed under the AGPL license, see LICENSE.txt
213
+
214
+ publibike.py
215
+ # Copyright (C) 2010-2026, eskerda <eskerda@gmail.com>
216
+ # Copyright (C) 2022-2023, eUgEntOptIc44 (https://github.com/eUgEntOptIc44)
217
+ # Distributed under the AGPL license, see LICENSE.txt
218
+
219
+ qrobici.py
220
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
221
+ # Distributed under the AGPL license, see LICENSE.txt
222
+
223
+ samba.py
224
+ # Original work Copyright (C) 2014, iomartin <iomartin@iomartin.net>
225
+ # Modified work Copyright (C) 2015 Eduardo Mucelli Rezende Oliveira <edumucelli@gmail.com>
226
+ # Modified work Copyright (C) 2023 Martín González Gómez <m@martingonzalez.net>
227
+ # Distributed under the AGPL license, see LICENSE.txt
228
+
229
+ sejong.py
230
+ # Distributed under the AGPL license, see LICENSE.txt
231
+ # Copyright (C) 2024, Martín González Gómez <m@martingonzalez.net>
232
+
233
+ seoulbike.py
234
+ # Distributed under the AGPL license, see LICENSE.txt
235
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
236
+
237
+ slovnaft_bajk.py
238
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
239
+ # Distributed under the AGPL license, see LICENSE.txt
240
+
241
+ smartbike.py
242
+ # Copyright (C) 2010-2012, eskerda <eskerda@gmail.com>
243
+ # Distributed under the AGPL license, see LICENSE.txt
244
+
245
+ smoove.py
246
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
247
+ # Copyright (C) 2019, Louis Turpinat <turpinat.louis@gmail.com>
248
+ # Copyright (C) 2016, Lluis Esquerda <eskerda@gmail.com>
249
+ # Copyright (C) 2015, Eduardo Mucelli Rezende Oliveira <edumucelli@gmail.com>
250
+ # Distributed under the AGPL license, see LICENSE.txt
251
+
252
+ soltrafego.py
253
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
254
+ # Distributed under the AGPL license, see LICENSE.txt
255
+
256
+ tashu.py
257
+ # Distributed under the AGPL license, see LICENSE.txt
258
+ # Copyright (C) 2024, Martín González Gómez <m@martingonzalez.net>
259
+
260
+ urbansharing.py
261
+ # Distributed under the AGPL license, see LICENSE.txt
262
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
263
+
264
+ utils.py
265
+ # Copyright (C) 2010-2012, eskerda <eskerda@gmail.com>
266
+ # Distributed under the AGPL license, see LICENSE.txt
267
+
268
+ veloway.py
269
+ # Copyright (C) 2010-2021, eskerda <eskerda@gmail.com>
270
+ # Distributed under the AGPL license, see LICENSE.txt
271
+
272
+ weelo.py
273
+ # Copyright (C) 2010-2023, eskerda <eskerda@gmail.com>
274
+ # Distributed under the AGPL license, see LICENSE.txt
275
+
276
+ wegoshare.py
277
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
278
+ # Distributed under the AGPL license, see LICENSE.txt
279
+
280
+ xian.py
281
+ # Copyright (C) 2024, Martín González Gómez <m@martingonzalez.net>
282
+ # Distributed under the AGPL license, see LICENSE.txt
283
+
284
+ yelovelo.py
285
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
286
+ # Distributed under the AGPL license, see LICENSE.txt
287
+
288
+ youbike.py
289
+ # Copyright (C) 2023, Martín González Gómez <m@martingonzalez.net>
290
+ # Distributed under the AGPL license, see LICENSE.txt