mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-12 06:12:18 +00:00
fix(transit): read Rouen and Le Havre from the operators' own feeds
Rouen now reads Métropole Rouen Normandie's TCAR vehicle feed (api.mrn.cityway.fr) and Le Havre LiA's own GTFS-RT (opendata.transports-lia.fr), both listed in their transport.data.gouv.fr records, instead of the unofficial bus-tracker.fr relay. LiA ids carry an 8- prefix, so a new liaRouteLabel strips it and liaRouteMode reads the line.
This commit is contained in:
1 parent
7a053c640d
commit
2c1b2c278d
3 files changed
+31
-24
No files matched your search
+2
-2
@@ -133,9 +133,9 @@ How to read this:
|
|||||||
| **Carris (Lisbon city)** (gateway.carris.pt) | Transit layer live vehicles, Lisbon, Portugal | No licence stated (https://mobilitydatabase.org/feeds/gtfs_rt/mdb-2930). Keyless official gateway; no licence found. Same basis as Metro Transit and OVapi. Carries neither bearing nor speed, and vehicle reports run about a minute old. Route ids append a variant. | Carris |
|
| **Carris (Lisbon city)** (gateway.carris.pt) | Transit layer live vehicles, Lisbon, Portugal | No licence stated (https://mobilitydatabase.org/feeds/gtfs_rt/mdb-2930). Keyless official gateway; no licence found. Same basis as Metro Transit and OVapi. Carries neither bearing nor speed, and vehicle reports run about a minute old. Route ids append a variant. | Carris |
|
||||||
| **BAS.MY Johor Bahru** (api.data.gov.my) | Transit layer live vehicles, Johor Bahru, Malaysia | CC BY 4.0 (https://developer.data.gov.my/realtime-api/gtfs-realtime). Stated: “All GTFS Realtime feeds are licensed under CC BY 4.0.” Served keyless by Malaysia’s national open-data API, which caps GTFS Realtime at 4 requests a minute and refreshes positions every 30 seconds, so the proxy caches this feed for 30 seconds. Without the trailing slash the API redirects. Route ids append an operator code. | BAS.MY / data.gov.my |
|
| **BAS.MY Johor Bahru** (api.data.gov.my) | Transit layer live vehicles, Johor Bahru, Malaysia | CC BY 4.0 (https://developer.data.gov.my/realtime-api/gtfs-realtime). Stated: “All GTFS Realtime feeds are licensed under CC BY 4.0.” Served keyless by Malaysia’s national open-data API, which caps GTFS Realtime at 4 requests a minute and refreshes positions every 30 seconds, so the proxy caches this feed for 30 seconds. Without the trailing slash the API redirects. Route ids append an operator code. | BAS.MY / data.gov.my |
|
||||||
| **BAS.MY Kota Bharu** (api.data.gov.my) | Transit layer live vehicles, Kota Bharu, Malaysia | CC BY 4.0 (https://developer.data.gov.my/realtime-api/gtfs-realtime). Same API, licence and rate limit as Johor Bahru. | BAS.MY / data.gov.my |
|
| **BAS.MY Kota Bharu** (api.data.gov.my) | Transit layer live vehicles, Kota Bharu, Malaysia | CC BY 4.0 (https://developer.data.gov.my/realtime-api/gtfs-realtime). Same API, licence and rate limit as Johor Bahru. | BAS.MY / data.gov.my |
|
||||||
| **Rouen Astuce** (gtfs.bus-tracker.fr) | Transit layer live vehicles, Rouen, France | Licence Ouverte 2.0 (https://transport.data.gouv.fr/datasets/donnees-statiques-et-temps-reel-du-reseau-astuce-metropole-rouen-normandie). The metropolis publishes its realtime data under the Licence Ouverte (dataset record quoted); this registry reads it through bus-tracker.fr, an unofficial relay that merges the city’s networks into one GTFS-RT file. Route ids carry the network prefix (`TCAR:`); line 90 is the Métro (a street-running light rail, drawn as a tram) and 99 the Calypso boat. | Métropole Rouen Normandie (Astuce) / bus-tracker.fr |
|
| **Rouen Astuce** (api.mrn.cityway.fr) | Transit layer live vehicles, Rouen, France | Licence Ouverte 2.0 (https://transport.data.gouv.fr/datasets/donnees-statiques-et-temps-reel-du-reseau-astuce-metropole-rouen-normandie). The metropolis publishes its realtime data under the Licence Ouverte (dataset record quoted); and this is its own TCAR vehicle feed from that record; the suburban TAE and TNI networks are separate feeds and are not read. Route ids carry the network prefix (`TCAR:`); line 90 is the Métro (a street-running light rail, drawn as a tram) and 99 the Calypso boat. | Métropole Rouen Normandie (Astuce) |
|
||||||
| **Toulon Mistral** (feed-rdtpm-toulon.ratpdev.com) | Transit layer live vehicles, Toulon, France | Licence Ouverte 2.0 (https://transport.data.gouv.fr/datasets/reseau-de-transport-urbain-de-la-metropole-toulon-provence-mediterranee). Dataset record’s licence field quoted. Speeds are km/h: readings ran 3.5 times the measured movement on 2026-11-07, so the proxy converts them. Route ids are zero-padded. | Métropole Toulon Provence Méditerranée (Mistral) |
|
| **Toulon Mistral** (feed-rdtpm-toulon.ratpdev.com) | Transit layer live vehicles, Toulon, France | Licence Ouverte 2.0 (https://transport.data.gouv.fr/datasets/reseau-de-transport-urbain-de-la-metropole-toulon-provence-mediterranee). Dataset record’s licence field quoted. Speeds are km/h: readings ran 3.5 times the measured movement on 2026-11-07, so the proxy converts them. Route ids are zero-padded. | Métropole Toulon Provence Méditerranée (Mistral) |
|
||||||
| **Le Havre LiA** (gtfs.bus-tracker.fr) | Transit layer live vehicles, Le Havre, France | ODbL (https://transport.data.gouv.fr/datasets/reseau-de-transport-en-commun-lia-gtfs-siri). The network publishes under ODbL (dataset record quoted); read through the bus-tracker.fr relay, which converts its SIRI feed to GTFS-RT. The layer draws positions and redistributes no database. Lines A and B are the tramway. | Le Havre Seine Métropole (LiA) / bus-tracker.fr |
|
| **Le Havre LiA** (opendata.transports-lia.fr) | Transit layer live vehicles, Le Havre, France | ODbL (https://transport.data.gouv.fr/datasets/reseau-de-transport-en-commun-lia-gtfs-siri). The network publishes under ODbL (dataset record quoted); and this is its own GTFS-RT vehicle feed from that record; route ids carry the network prefix `8-`. The layer draws positions and redistributes no database. Lines A and B are the tramway. | Le Havre Seine Métropole (LiA) |
|
||||||
| **Tours Fil Bleu** (data.filbleu.fr) | Transit layer live vehicles, Tours, France | Licence Ouverte 2.0 (https://transport.data.gouv.fr/datasets/fil-bleu-syndicat-des-mobilites-gtfs-gtfs-rt). Dataset record’s licence field quoted. | Fil Bleu – Syndicat des Mobilités de Touraine |
|
| **Tours Fil Bleu** (data.filbleu.fr) | Transit layer live vehicles, Tours, France | Licence Ouverte 2.0 (https://transport.data.gouv.fr/datasets/fil-bleu-syndicat-des-mobilites-gtfs-gtfs-rt). Dataset record’s licence field quoted. | Fil Bleu – Syndicat des Mobilités de Touraine |
|
||||||
| **Radio Browser** | Geolocated internet-radio station directory and station-level tags | Public-domain directory data under PDDL 1.0; individual broadcaster stream terms apply | "Radio Browser" plus a link to the selected broadcaster |
|
| **Radio Browser** | Geolocated internet-radio station directory and station-level tags | Public-domain directory data under PDDL 1.0; individual broadcaster stream terms apply | "Radio Browser" plus a link to the selected broadcaster |
|
||||||
| **Re:Earth Terrain** (Mapterhorn) | Terrain (keyless globe stacks — OSM etc. — + `/api/terrain/heights` ellipsoidal-height lookups) | Terrain mesh: CC BY 4.0; geoid: EGM2008 (NGA, public domain) | "Terrain (keyless globe stacks): Re:Earth Terrain / Mapterhorn (CC BY 4.0) / EGM2008 (NGA)" |
|
| **Re:Earth Terrain** (Mapterhorn) | Terrain (keyless globe stacks — OSM etc. — + `/api/terrain/heights` ellipsoidal-height lookups) | Terrain mesh: CC BY 4.0; geoid: EGM2008 (NGA, public domain) | "Terrain (keyless globe stacks): Re:Earth Terrain / Mapterhorn (CC BY 4.0) / EGM2008 (NGA)" |
|
||||||
|
|||||||
+21
-18
@@ -426,11 +426,14 @@ const actvRouteLabel = routeIdPattern(/^(.+)_[A-Z]{2}$/);
|
|||||||
const bcTransitRouteLabel = routeIdPattern(/^(.+)-VIC$/);
|
const bcTransitRouteLabel = routeIdPattern(/^(.+)-VIC$/);
|
||||||
/** Carris (Lisbon city) appends a variant: `172_1` is route 172. */
|
/** Carris (Lisbon city) appends a variant: `172_1` is route 172. */
|
||||||
const carrisRouteLabel = routeIdPattern(/^(\w+)_\d+$/);
|
const carrisRouteLabel = routeIdPattern(/^(\w+)_\d+$/);
|
||||||
/** bus-tracker.fr prefixes the network: `TCAR:93` is Rouen line 93. */
|
/** Astuce prefixes the network: `TCAR:93` is Rouen line 93. */
|
||||||
const busTrackerRouteLabel = routeIdPattern(/^[A-Z]+:(.+)$/);
|
const astuceNetworkLabel = routeIdPattern(/^[A-Z]+:(.+)$/);
|
||||||
/** BAS.MY Johor appends a fixed operator code: `J33CWLMYJB` is route J33. */
|
/** BAS.MY Johor appends a fixed operator code: `J33CWLMYJB` is route J33. */
|
||||||
const mybasJohorRouteLabel = routeIdPattern(/^(.+?)CWLMYJB$/);
|
const mybasJohorRouteLabel = routeIdPattern(/^(.+?)CWLMYJB$/);
|
||||||
|
|
||||||
|
/** LiA prefixes its network: `8-C3` is Le Havre line C3, `8-09` line 9. */
|
||||||
|
const liaRouteLabel = routeIdPattern(/^8-0*(\w.*)$/);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Le Havre LiA runs its two tram lines as A and B and the funicular as
|
* Le Havre LiA runs its two tram lines as A and B and the funicular as
|
||||||
* `FUNI`; every other line is a bus.
|
* `FUNI`; every other line is a bus.
|
||||||
@@ -439,15 +442,15 @@ const mybasJohorRouteLabel = routeIdPattern(/^(.+?)CWLMYJB$/);
|
|||||||
*/
|
*/
|
||||||
function liaRouteMode(routeId) {
|
function liaRouteMode(routeId) {
|
||||||
if (!routeId) return 'unknown';
|
if (!routeId) return 'unknown';
|
||||||
if (routeId === 'FUNI') return 'rail';
|
const line = liaRouteLabel(routeId);
|
||||||
return /^(?:[A-Z]+:)?[AB]$/.test(routeId) ? 'tram' : 'bus';
|
if (line === 'FUNI') return 'rail';
|
||||||
|
return /^[AB]$/.test(line) ? 'tram' : 'bus';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rouen Astuce lines that are not buses, by bus-tracker.fr route id, from the
|
* Rouen Astuce lines that are not buses, by route id, from the TCAR
|
||||||
* relay's own `astuce-tcar.zip` routes.txt (checked 2026-11-09): line 90 is
|
* routes.txt (checked 2026-11-09): line 90 is the Métro (GTFS type 1, a light
|
||||||
* the Métro (GTFS type 1, a light rail that runs mostly on the street) and 99
|
* rail that runs mostly on the street) and 99 the Calypso river boat.
|
||||||
* the Calypso river boat.
|
|
||||||
*/
|
*/
|
||||||
const ASTUCE_ROUTES = Object.freeze({
|
const ASTUCE_ROUTES = Object.freeze({
|
||||||
'TCAR:90': Object.freeze({ mode: 'tram', label: 'Métro' }),
|
'TCAR:90': Object.freeze({ mode: 'tram', label: 'Métro' }),
|
||||||
@@ -462,7 +465,7 @@ function astuceRouteMode(routeId) {
|
|||||||
|
|
||||||
/** `TCAR:93` is Rouen line 93; the Métro and Calypso keep their names. */
|
/** `TCAR:93` is Rouen line 93; the Métro and Calypso keep their names. */
|
||||||
function astuceRouteLabel(routeId) {
|
function astuceRouteLabel(routeId) {
|
||||||
return ASTUCE_ROUTES[routeId ?? '']?.label ?? busTrackerRouteLabel(routeId);
|
return ASTUCE_ROUTES[routeId ?? '']?.label ?? astuceNetworkLabel(routeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1504,18 +1507,18 @@ export const TRANSIT_FEED_REGISTRY = Object.freeze([
|
|||||||
transitFeed({
|
transitFeed({
|
||||||
id: 'astuce-rouen',
|
id: 'astuce-rouen',
|
||||||
name: 'Rouen Astuce',
|
name: 'Rouen Astuce',
|
||||||
operator: 'Métropole Rouen Normandie (Astuce), relayed by bus-tracker.fr',
|
operator: 'Métropole Rouen Normandie (Astuce), réseau TCAR',
|
||||||
region: 'Rouen, France',
|
region: 'Rouen, France',
|
||||||
center: { lat: 49.44, lon: 1.1 },
|
center: { lat: 49.44, lon: 1.1 },
|
||||||
loadRadiusKm: 20,
|
loadRadiusKm: 20,
|
||||||
url: 'https://gtfs.bus-tracker.fr/gtfs-rt/tcar/?tcar=1&tae=1&tni=1',
|
url: 'https://api.mrn.cityway.fr/dataflow/vehicle-tc-tr/download?provider=TCAR&dataFormat=gtfs-rt',
|
||||||
license: 'Licence Ouverte 2.0',
|
license: 'Licence Ouverte 2.0',
|
||||||
licenseUrl:
|
licenseUrl:
|
||||||
'https://transport.data.gouv.fr/datasets/donnees-statiques-et-temps-reel-du-reseau-astuce-metropole-rouen-normandie',
|
'https://transport.data.gouv.fr/datasets/donnees-statiques-et-temps-reel-du-reseau-astuce-metropole-rouen-normandie',
|
||||||
attribution: 'Métropole Rouen Normandie (Astuce) / bus-tracker.fr',
|
attribution: 'Métropole Rouen Normandie (Astuce)',
|
||||||
terms: {
|
terms: {
|
||||||
quote: 'licence: lov2',
|
quote: 'licence: lov2',
|
||||||
note: 'The metropolis publishes its realtime data under the Licence Ouverte (dataset record quoted); this registry reads it through bus-tracker.fr, an unofficial relay that merges the city’s networks into one GTFS-RT file. Route ids carry the network prefix (`TCAR:`); `TCAR:90` is the Métro (a street-running light rail, drawn as a tram) and `TCAR:99` the Calypso boat.',
|
note: 'The metropolis publishes its realtime data under the Licence Ouverte (dataset record quoted), and this is its own TCAR vehicle feed from that record (178 vehicles on 2026-11-09). The suburban TAE and TNI networks are separate feeds in the same record and are not read here. Route ids carry the network prefix (`TCAR:`); `TCAR:90` is the Métro (a street-running light rail, drawn as a tram) and `TCAR:99` the Calypso boat.',
|
||||||
},
|
},
|
||||||
defaultMode: 'bus',
|
defaultMode: 'bus',
|
||||||
routeLabel: astuceRouteLabel,
|
routeLabel: astuceRouteLabel,
|
||||||
@@ -1544,21 +1547,21 @@ export const TRANSIT_FEED_REGISTRY = Object.freeze([
|
|||||||
transitFeed({
|
transitFeed({
|
||||||
id: 'lia-le-havre',
|
id: 'lia-le-havre',
|
||||||
name: 'Le Havre LiA',
|
name: 'Le Havre LiA',
|
||||||
operator: 'Le Havre Seine Métropole (LiA), relayed by bus-tracker.fr',
|
operator: 'Le Havre Seine Métropole (LiA)',
|
||||||
region: 'Le Havre, France',
|
region: 'Le Havre, France',
|
||||||
center: { lat: 49.49, lon: 0.11 },
|
center: { lat: 49.49, lon: 0.11 },
|
||||||
loadRadiusKm: 18,
|
loadRadiusKm: 18,
|
||||||
url: 'https://gtfs.bus-tracker.fr/gtfs-rt/lia/vehicle-positions',
|
url: 'https://opendata.transports-lia.fr/gtfs-rt/VehiclePosition.pb',
|
||||||
license: 'ODbL',
|
license: 'ODbL',
|
||||||
licenseUrl:
|
licenseUrl:
|
||||||
'https://transport.data.gouv.fr/datasets/reseau-de-transport-en-commun-lia-gtfs-siri',
|
'https://transport.data.gouv.fr/datasets/reseau-de-transport-en-commun-lia-gtfs-siri',
|
||||||
attribution: 'Le Havre Seine Métropole (LiA) / bus-tracker.fr',
|
attribution: 'Le Havre Seine Métropole (LiA)',
|
||||||
terms: {
|
terms: {
|
||||||
quote: 'licence: odc-odbl',
|
quote: 'licence: odc-odbl',
|
||||||
note: 'The network publishes under ODbL (dataset record quoted); read through the bus-tracker.fr relay, which converts its SIRI feed to GTFS-RT. The layer draws positions and redistributes no database. Lines A and B are the tramway.',
|
note: 'The network publishes under ODbL (dataset record quoted), and this is its own GTFS-RT vehicle feed from that record (105 vehicles on 2026-11-09). The layer draws positions and redistributes no database. Route ids carry the network prefix `8-`; lines A and B are the tramway.',
|
||||||
},
|
},
|
||||||
defaultMode: 'bus',
|
defaultMode: 'bus',
|
||||||
routeLabel: busTrackerRouteLabel,
|
routeLabel: liaRouteLabel,
|
||||||
routeMode: liaRouteMode,
|
routeMode: liaRouteMode,
|
||||||
}),
|
}),
|
||||||
transitFeed({
|
transitFeed({
|
||||||
|
|||||||
@@ -702,8 +702,8 @@ test('trams, waterbuses and buses are told apart where the ids allow it', () =>
|
|||||||
assert.equal(mode('pid-praha', 'L22'), 'tram');
|
assert.equal(mode('pid-praha', 'L22'), 'tram');
|
||||||
assert.equal(mode('pid-praha', 'L135'), 'bus');
|
assert.equal(mode('pid-praha', 'L135'), 'bus');
|
||||||
assert.equal(mode('tbm-bordeaux', '16'), 'bus');
|
assert.equal(mode('tbm-bordeaux', '16'), 'bus');
|
||||||
assert.equal(mode('lia-le-havre', 'B'), 'tram');
|
assert.equal(mode('lia-le-havre', '8-B'), 'tram');
|
||||||
assert.equal(mode('lia-le-havre', '3'), 'bus');
|
assert.equal(mode('lia-le-havre', '8-C3'), 'bus');
|
||||||
assert.equal(mode('ztp-krakow-tram', null), 'tram');
|
assert.equal(mode('ztp-krakow-tram', null), 'tram');
|
||||||
assert.equal(mode('actv-venezia-waterbus', '1_UN'), 'ferry');
|
assert.equal(mode('actv-venezia-waterbus', '1_UN'), 'ferry');
|
||||||
});
|
});
|
||||||
@@ -759,14 +759,18 @@ test('Bordeaux trams ride numbered route ids and keep their letters', () => {
|
|||||||
assert.equal(transitRouteLabel(feed, '01'), '1');
|
assert.equal(transitRouteLabel(feed, '01'), '1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Rouen Métro and Calypso are not buses', () => {
|
test('Rouen Métro and Calypso are not buses; Le Havre reads its own ids', () => {
|
||||||
const feed = getTransitFeed('astuce-rouen');
|
const feed = getTransitFeed('astuce-rouen');
|
||||||
assert.equal(transitModeFor(feed, 'TCAR:90'), 'tram');
|
assert.equal(transitModeFor(feed, 'TCAR:90'), 'tram');
|
||||||
assert.equal(transitRouteLabel(feed, 'TCAR:90'), 'Métro');
|
assert.equal(transitRouteLabel(feed, 'TCAR:90'), 'Métro');
|
||||||
assert.equal(transitModeFor(feed, 'TCAR:99'), 'ferry');
|
assert.equal(transitModeFor(feed, 'TCAR:99'), 'ferry');
|
||||||
assert.equal(transitModeFor(feed, 'TCAR:93'), 'bus');
|
assert.equal(transitModeFor(feed, 'TCAR:93'), 'bus');
|
||||||
assert.equal(transitRouteLabel(feed, 'TAE:F'), 'F');
|
assert.equal(transitRouteLabel(feed, 'TAE:F'), 'F');
|
||||||
assert.equal(transitModeFor(getTransitFeed('lia-le-havre'), 'FUNI'), 'rail');
|
const lia = getTransitFeed('lia-le-havre');
|
||||||
|
assert.equal(transitModeFor(lia, '8-FUNI'), 'rail');
|
||||||
|
assert.equal(transitRouteLabel(lia, '8-C3'), 'C3');
|
||||||
|
assert.equal(transitRouteLabel(lia, '8-09'), '9');
|
||||||
|
assert.equal(transitRouteLabel(lia, '8-A'), 'A');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('data.gov.my feeds ask the proxy for no more than its 4 a minute', () => {
|
test('data.gov.my feeds ask the proxy for no more than its 4 a minute', () => {
|
||||||
|
|||||||
Reference in new issue
Block a user