PATCH v1.0.1 //
-> Amélioration de la mise en relation des TYPES DE TRAINS PAR CODE DE CIRCULATION (BETA)
This commit is contained in:
1 parent
d7d4f9cecf
commit
c30a0e9002
32 files changed
+2042
-532
No files matched your search
@@ -0,0 +1,935 @@
|
||||
/**
|
||||
* Moteur de classification et de corrélation des types de trains et opérateurs ferroviaires
|
||||
* ferrovia-infogare - Compatible afficheurs classiques (Hall & Quai)
|
||||
*
|
||||
* Hiérarchie de décision :
|
||||
* 1. Codes d'exploitation GTFS officiels (trip_id SNCF Open Data)
|
||||
* 2. Détection des services spécifiques (Lyria, Ouigo Classique, Intercités de Nuit, etc.)
|
||||
* 3. Plan de Numérotation officiel SNCF (séries régionales TER hermétiques par blocs de numéros)
|
||||
* 4. Détection géographique par score d'arrêts et de terminus (sans faux-positifs)
|
||||
* 5. Re-routage vers TER générique ou SNCF Voyageurs en dernier recours
|
||||
*/
|
||||
|
||||
// Normalisation des chaînes (minuscules, sans accents, espaces normalisés)
|
||||
export const normalize = (str) => {
|
||||
if (!str) return '';
|
||||
return String(str)
|
||||
.toLowerCase()
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
.replace(/[^a-z0-9]/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
};
|
||||
|
||||
// Extraction des chiffres d'un numéro de train (sans zéros initiaux)
|
||||
export const extractTrainDigits = (num) => {
|
||||
if (!num) return '';
|
||||
const digits = String(num).replace(/\D/g, '');
|
||||
return digits.replace(/^0+/, '') || digits;
|
||||
};
|
||||
|
||||
// Services routiers par autocar (3xxxx / 3xxxxx)
|
||||
export const isCarTrainNumber = (num) => {
|
||||
const d = String(num || '').replace(/\D/g, '');
|
||||
return (d.length === 5 && d.startsWith('3')) || (d.length === 6 && d.startsWith('3'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Référentiel des marques, types de trains et logos (monochrome Hall & couleur Quai)
|
||||
*/
|
||||
export const BRANDS = {
|
||||
INOUi: {
|
||||
id: 'inoui',
|
||||
typeLabel: 'TGV inOUI',
|
||||
quaiLabel: 'TGV INOUI',
|
||||
operator: 'SNCF Voyageurs',
|
||||
category: 'TGV',
|
||||
isTgv: true,
|
||||
hallLogo: '/type/logo-inoui.svg',
|
||||
quaiLogo: '/type/quais/logo-inoui-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
TGV_GENERIC: {
|
||||
id: 'tgv',
|
||||
typeLabel: 'TGV',
|
||||
quaiLabel: 'TGV',
|
||||
operator: 'SNCF Voyageurs',
|
||||
category: 'TGV',
|
||||
isTgv: true,
|
||||
hallLogo: '/type/logo-tgv.svg',
|
||||
quaiLogo: '/type/quais/logo-tgv-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
LYRIA: {
|
||||
id: 'lyria',
|
||||
typeLabel: 'TGV Lyria',
|
||||
quaiLabel: 'TGV Lyria',
|
||||
operator: 'Lyria SAS',
|
||||
category: 'TGV',
|
||||
isTgv: true,
|
||||
hallLogo: '/type/logo-lyria.svg',
|
||||
quaiLogo: '/type/quais/logo-lyria-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
OUIGO_CLASSIQUE: {
|
||||
id: 'ouigo-classique',
|
||||
typeLabel: 'OUIGO Train Classique',
|
||||
quaiLabel: 'OUIGO Classique',
|
||||
operator: 'SNCF Voyageurs',
|
||||
category: 'GRANDES_LIGNES',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-ouigo-classique.svg',
|
||||
quaiLogo: '/type/quais/logo-ouigo-classique-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
OUIGO_GV: {
|
||||
id: 'ouigo',
|
||||
typeLabel: 'OUIGO',
|
||||
quaiLabel: 'OUIGO',
|
||||
operator: 'SNCF Voyageurs',
|
||||
category: 'TGV',
|
||||
isTgv: true,
|
||||
hallLogo: '/type/logo-ouigo.svg',
|
||||
quaiLogo: '/type/quais/logo-ouigo-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
INTERCITES_NUIT: {
|
||||
id: 'intercites-nuit',
|
||||
typeLabel: 'INTERCITÉS DE NUIT',
|
||||
quaiLabel: 'Intercités de Nuit',
|
||||
operator: 'SNCF Voyageurs',
|
||||
category: 'GRANDES_LIGNES',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-lunea.svg',
|
||||
quaiLogo: '/type/quais/logo-lunea-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
INTERCITES: {
|
||||
id: 'intercites',
|
||||
typeLabel: 'INTERCITÉS',
|
||||
quaiLabel: 'INTERCITÉS',
|
||||
operator: 'SNCF Voyageurs',
|
||||
category: 'GRANDES_LIGNES',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-intercites.svg',
|
||||
quaiLogo: '/type/quais/logo-intercite-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
EUROSTAR: {
|
||||
id: 'eurostar',
|
||||
typeLabel: 'EUROSTAR',
|
||||
quaiLabel: 'Eurostar',
|
||||
operator: 'Eurostar Group',
|
||||
category: 'INTERNATIONAL',
|
||||
isTgv: true,
|
||||
hallLogo: '/type/logo-eurostar.svg',
|
||||
quaiLogo: '/type/quais/logo-eurostar-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
THALYS: {
|
||||
id: 'thalys',
|
||||
typeLabel: 'THALYS',
|
||||
quaiLabel: 'Thalys',
|
||||
operator: 'Eurostar Group',
|
||||
category: 'INTERNATIONAL',
|
||||
isTgv: true,
|
||||
hallLogo: '/type/logo-thalys.svg',
|
||||
quaiLogo: '/type/quais/logo-thalys-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
ICE: {
|
||||
id: 'ice',
|
||||
typeLabel: 'ICE',
|
||||
quaiLabel: 'ICE',
|
||||
operator: 'DB / SNCF',
|
||||
category: 'INTERNATIONAL',
|
||||
isTgv: true,
|
||||
hallLogo: '/type/logo-ice.svg',
|
||||
quaiLogo: '/type/quais/logo-ice-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
DB: {
|
||||
id: 'db',
|
||||
typeLabel: 'DB',
|
||||
quaiLabel: 'DB',
|
||||
operator: 'Deutsche Bahn',
|
||||
category: 'INTERNATIONAL',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-db.svg',
|
||||
quaiLogo: '/type/quais/logo-db-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
FRECCIAROSSA: {
|
||||
id: 'frecciarossa',
|
||||
typeLabel: 'FRECCIAROSSA',
|
||||
quaiLabel: 'Frecciarossa',
|
||||
operator: 'Trenitalia France',
|
||||
category: 'INTERNATIONAL',
|
||||
isTgv: true,
|
||||
hallLogo: '/type/logo-frecciarossa.svg',
|
||||
quaiLogo: '/type/quais/logo-frecciarossa-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
RENFE_AVE: {
|
||||
id: 'renfe-ave',
|
||||
typeLabel: 'Renfe AVE',
|
||||
quaiLabel: 'Renfe AVE',
|
||||
operator: 'Renfe',
|
||||
category: 'INTERNATIONAL',
|
||||
isTgv: true,
|
||||
hallLogo: '/type/logo-renfeave.svg',
|
||||
quaiLogo: '/type/quais/logo-renfeave-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
AUTOCAR: {
|
||||
id: 'autocar',
|
||||
typeLabel: 'AUTOCAR',
|
||||
quaiLabel: 'Autocar',
|
||||
operator: 'SNCF Voyageurs',
|
||||
category: 'AUTOCAR',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/track-car.svg',
|
||||
quaiLogo: '/type/track-car.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
TRAMTRAIN: {
|
||||
id: 'tramtrain',
|
||||
typeLabel: 'Tram-train',
|
||||
quaiLabel: 'Tram-train',
|
||||
operator: 'TER',
|
||||
category: 'TER',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-tramtrain.svg',
|
||||
quaiLogo: '/type/quais/logo-tramtrain-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
MOBIGO: {
|
||||
id: 'mobigo',
|
||||
typeLabel: 'MOBIGO',
|
||||
quaiLabel: 'Mobigo',
|
||||
operator: 'Région Bourgogne-Franche-Comté',
|
||||
category: 'TER',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-mobigo.svg',
|
||||
quaiLogo: '/type/quais/logo-mobigo-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
ZOU: {
|
||||
id: 'zou',
|
||||
typeLabel: 'ZOU !',
|
||||
quaiLabel: 'ZOU!',
|
||||
operator: 'Région Sud / PACA',
|
||||
category: 'TER',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-zou.svg',
|
||||
quaiLogo: '/type/quais/logo-zou-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
FLUO: {
|
||||
id: 'fluo',
|
||||
typeLabel: 'FLUO',
|
||||
quaiLabel: 'TER Fluo',
|
||||
operator: 'Région Grand Est',
|
||||
category: 'TER',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-fluo.svg',
|
||||
quaiLogo: '/type/quais/logo-fluo-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
ALEOP: {
|
||||
id: 'aleop',
|
||||
typeLabel: 'ALÉOP',
|
||||
quaiLabel: 'Aléop',
|
||||
operator: 'Région Pays de la Loire',
|
||||
category: 'TER',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-aleop.svg',
|
||||
quaiLogo: '/type/quais/logo-aleop-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
BREIZHGO: {
|
||||
id: 'breizhgo',
|
||||
typeLabel: 'BREIZHGO',
|
||||
quaiLabel: 'BreizhGo',
|
||||
operator: 'Région Bretagne',
|
||||
category: 'TER',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-breizhgo.svg',
|
||||
quaiLogo: '/type/quais/logo-breizhgo-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
NOMAD: {
|
||||
id: 'nomad',
|
||||
typeLabel: 'NOMAD',
|
||||
quaiLabel: 'Nomad',
|
||||
operator: 'Région Normandie',
|
||||
category: 'TER',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-nomad.svg',
|
||||
quaiLogo: '/type/quais/logo-nomad-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
REMI: {
|
||||
id: 'remi',
|
||||
typeLabel: 'RÉMI',
|
||||
quaiLabel: 'Rémi',
|
||||
operator: 'Région Centre-Val de Loire',
|
||||
category: 'TER',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-remi.svg',
|
||||
quaiLogo: '/type/quais/logo-remi-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
LIO: {
|
||||
id: 'lio',
|
||||
typeLabel: 'LIÒ',
|
||||
quaiLabel: 'liO',
|
||||
operator: 'Région Occitanie',
|
||||
category: 'TER',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-lio.svg',
|
||||
quaiLogo: '/type/quais/logo-lio-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
HAUTS_DE_FRANCE: {
|
||||
id: 'hautsdefrance',
|
||||
typeLabel: 'HAUTS-DE-FRANCE',
|
||||
quaiLabel: 'Hauts-de-France',
|
||||
operator: 'Région Hauts-de-France',
|
||||
category: 'TER',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-hautsdefrance.svg',
|
||||
quaiLogo: '/type/quais/logo-hautsdefrance-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
AUVERGNE_RHONE_ALPES: {
|
||||
id: 'auvergerhonealpes',
|
||||
typeLabel: 'AUVERGNE-RHÔNE-ALPES',
|
||||
quaiLabel: 'Auvergne-Rhône-Alpes',
|
||||
operator: 'Région Auvergne-Rhône-Alpes',
|
||||
category: 'TER',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-auvergerhonealpes.svg',
|
||||
quaiLogo: '/type/quais/logo-auvergerhonealpes-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
NOUVELLE_AQUITAINE: {
|
||||
id: 'nouvelleaquitaine',
|
||||
typeLabel: 'NOUVELLE-AQUITAINE',
|
||||
quaiLabel: 'Nouvelle-Aquitaine',
|
||||
operator: 'Région Nouvelle-Aquitaine',
|
||||
category: 'TER',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-teraquitaine.svg',
|
||||
quaiLogo: '/type/quais/logo-nouvelleaquitaine-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
TER_GENERIC: {
|
||||
id: 'ter',
|
||||
typeLabel: 'TER',
|
||||
quaiLabel: 'TER',
|
||||
operator: 'SNCF Voyageurs',
|
||||
category: 'TER',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-ter.svg',
|
||||
quaiLogo: '/type/quais/logo-ter-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
SBB: {
|
||||
id: 'sbb',
|
||||
typeLabel: 'SBB',
|
||||
quaiLabel: 'SBB',
|
||||
operator: 'CFF / SBB',
|
||||
category: 'INTERNATIONAL',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-sbb.svg',
|
||||
quaiLogo: '/type/quais/logo-sbb-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
SNCB: {
|
||||
id: 'sncb',
|
||||
typeLabel: 'SNCB',
|
||||
quaiLabel: 'SNCB',
|
||||
operator: 'SNCB / NMBS',
|
||||
category: 'INTERNATIONAL',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-sncb.svg',
|
||||
quaiLogo: '/type/quais/logo-sncb-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
CFL: {
|
||||
id: 'cfl',
|
||||
typeLabel: 'CFL',
|
||||
quaiLabel: 'CFL',
|
||||
operator: 'CFL',
|
||||
category: 'INTERNATIONAL',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-cfl.svg',
|
||||
quaiLogo: '/type/quais/logo-cfl-color.svg',
|
||||
showVoyageursText: false
|
||||
},
|
||||
SNCF_GENERIC: {
|
||||
id: 'sncf',
|
||||
typeLabel: 'SNCF',
|
||||
quaiLabel: 'SNCF',
|
||||
operator: 'SNCF Voyageurs',
|
||||
category: 'SNCF',
|
||||
isTgv: false,
|
||||
hallLogo: '/type/logo-sncf.svg',
|
||||
quaiLogo: '/type/quais/logo-sncf-color.svg',
|
||||
showVoyageursText: true
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Plan de Numérotation officiel SNCF (Séries régionales TER)
|
||||
* Chaque autorité organisatrice régionale dispose de tranches numériques réservées.
|
||||
*/
|
||||
function getRegionByTrainNumber(numStr) {
|
||||
const clean = String(numStr || '').replace(/\D/g, '');
|
||||
if (!clean || clean.length < 3) return null;
|
||||
|
||||
// 1. Occitanie (liO) : 869xxx, 870xxx, 871xxx, 872xxx, 876xxx, 877xxx (et 5 chiffres : 869xx, 870xx, 876xx, 877xx)
|
||||
if (
|
||||
clean.startsWith('869') ||
|
||||
clean.startsWith('870') ||
|
||||
clean.startsWith('871') ||
|
||||
clean.startsWith('872') ||
|
||||
clean.startsWith('876') ||
|
||||
clean.startsWith('877')
|
||||
) {
|
||||
return BRANDS.LIO;
|
||||
}
|
||||
|
||||
// 2. Centre-Val de Loire (Rémi) : 860xxx, 861xxx, 862xxx, 863xxx (et 860xx à 863xx)
|
||||
if (
|
||||
clean.startsWith('860') ||
|
||||
clean.startsWith('861') ||
|
||||
clean.startsWith('862') ||
|
||||
clean.startsWith('863')
|
||||
) {
|
||||
return BRANDS.REMI;
|
||||
}
|
||||
|
||||
// 3. Nouvelle-Aquitaine : 864xxx, 865xxx, 866xxx, 867xxx, 868xxx (et 864xx à 868xx)
|
||||
if (
|
||||
clean.startsWith('864') ||
|
||||
clean.startsWith('865') ||
|
||||
clean.startsWith('866') ||
|
||||
clean.startsWith('867') ||
|
||||
clean.startsWith('868')
|
||||
) {
|
||||
return BRANDS.NOUVELLE_AQUITAINE;
|
||||
}
|
||||
|
||||
// 4. Grand Est (Fluo) : 83xxxx (et 83xxx)
|
||||
if (clean.startsWith('83')) {
|
||||
return BRANDS.FLUO;
|
||||
}
|
||||
|
||||
// 5. Bourgogne-Franche-Comté (Mobigo) : 89xxxx, 840xxx, 841xxx (et 89xxx, 840xx, 841xx)
|
||||
if (
|
||||
clean.startsWith('89') ||
|
||||
clean.startsWith('840') ||
|
||||
clean.startsWith('841')
|
||||
) {
|
||||
return BRANDS.MOBIGO;
|
||||
}
|
||||
|
||||
// 6. Hauts-de-France : 842xxx à 849xxx (et 842xx à 849xx)
|
||||
if (['842', '843', '844', '845', '846', '847', '848', '849'].some(p => clean.startsWith(p))) {
|
||||
return BRANDS.HAUTS_DE_FRANCE;
|
||||
}
|
||||
|
||||
// 7. Normandie (Nomad) : 852xxx, 853xxx (et 852xx, 853xx)
|
||||
if (clean.startsWith('852') || clean.startsWith('853')) {
|
||||
return BRANDS.NOMAD;
|
||||
}
|
||||
|
||||
// 8. Bretagne (BreizhGo) : 854xxx, 855xxx, 856xxx (et 854xx à 856xx)
|
||||
if (clean.startsWith('854') || clean.startsWith('855') || clean.startsWith('856')) {
|
||||
return BRANDS.BREIZHGO;
|
||||
}
|
||||
|
||||
// 9. Pays de la Loire (Aléop) : 857xxx, 858xxx, 859xxx (et 857xx à 859xx)
|
||||
if (clean.startsWith('857') || clean.startsWith('858') || clean.startsWith('859')) {
|
||||
return BRANDS.ALEOP;
|
||||
}
|
||||
|
||||
// 10. Auvergne-Rhône-Alpes : 873xxx à 875xxx, 883xxx, 884xxx, 889xxx
|
||||
if (['873', '874', '875', '883', '884', '889'].some(p => clean.startsWith(p))) {
|
||||
return BRANDS.AUVERGNE_RHONE_ALPES;
|
||||
}
|
||||
|
||||
// 11. PACA / Sud (Zou !) : 880xxx, 881xxx, 882xxx, 885xxx, 886xxx, 887xxx, 888xxx
|
||||
if (['880', '881', '882', '885', '886', '887', '888'].some(p => clean.startsWith(p))) {
|
||||
return BRANDS.ZOU;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gares de référence par région ferroviaire pour analyse de parcours
|
||||
* (Seuls des noms de villes ou gares réelles sans mots génériques comme 'centre' ou 'est')
|
||||
*/
|
||||
const REGIONAL_STATIONS = {
|
||||
lio: [
|
||||
'perpignan', 'narbonne', 'toulouse', 'nimes', 'beziers', 'sete', 'montpellier',
|
||||
'cerbere', 'portbou', 'villefranche', 'carcassonne', 'agde', 'elne', 'argeles',
|
||||
'collioure', 'port vendres', 'banyuls', 'rodez', 'albi', 'tarbes', 'montauban',
|
||||
'castres', 'lourdes', 'mende', 'foix', 'latour de carol', 'ax les thermes',
|
||||
'castelnaudary', 'frontignan', 'port la nouvelle', 'leucate', 'salses', 'rivesaltes'
|
||||
],
|
||||
remi: [
|
||||
'orleans', 'tours', 'bourges', 'blois', 'chartres', 'chateauroux', 'vierzon',
|
||||
'vendome', 'saint pierre des corps', 'amboise', 'nogent le rotrou', 'salbris',
|
||||
'chinon', 'loches', 'issoudun', 'romorantin', 'montargis', 'gien'
|
||||
],
|
||||
mobigo: [
|
||||
'dijon', 'besancon', 'belfort', 'auxerre', 'nevers', 'chalon sur saone',
|
||||
'montbeliard', 'macon', 'sens', 'dole', 'creusot', 'paray le monial',
|
||||
'beaune', 'lons le saunier', 'pontarlier', 'vesoul'
|
||||
],
|
||||
zou: [
|
||||
'marseille', 'nice', 'toulon', 'cannes', 'antibes', 'avignon', 'grasse',
|
||||
'aubagne', 'miramas', 'arles', 'hyeres', 'menton', 'cagnes sur mer',
|
||||
'frejus', 'saint raphael', 'la ciotat', 'gap', 'briancon', 'manosque'
|
||||
],
|
||||
fluo: [
|
||||
'strasbourg', 'nancy', 'metz', 'mulhouse', 'colmar', 'reims', 'troyes',
|
||||
'epinal', 'thionville', 'charleville', 'saint die', 'haguenau',
|
||||
'sarreguemines', 'bar le duc', 'luneville', 'sedan', 'forbach', 'selestat'
|
||||
],
|
||||
aleop: [
|
||||
'nantes', 'angers', 'le mans', 'saint nazaire', 'cholet', 'la roche sur yon',
|
||||
'saumur', 'laval', 'les sables d olonne', 'ancenis', 'clisson', 'chateaubriant'
|
||||
],
|
||||
breizhgo: [
|
||||
'rennes', 'brest', 'quimper', 'saint malo', 'vannes', 'lorient',
|
||||
'saint brieuc', 'morlaix', 'lannion', 'vitre', 'redon', 'guingamp'
|
||||
],
|
||||
nomad: [
|
||||
'rouen', 'caen', 'le havre', 'cherbourg', 'evreux', 'trouville deauville',
|
||||
'dieppe', 'lisieux', 'granville', 'alencon', 'bernay', 'bayeux'
|
||||
],
|
||||
hautsdefrance: [
|
||||
'lille', 'amiens', 'calais', 'dunkerque', 'valenciennes', 'arras',
|
||||
'boulogne sur mer', 'douai', 'creil', 'saint quentin', 'lens', 'bethune',
|
||||
'compiegne', 'cambrai', 'tourcoing', 'roubaix'
|
||||
],
|
||||
auvergerhonealpes: [
|
||||
'lyon', 'grenoble', 'chambery', 'annecy', 'valence', 'clermont ferrand',
|
||||
'saint etienne', 'bourg en bresse', 'roanne', 'vichy', 'aix les bains',
|
||||
'annemasse', 'amberieu', 'riom', 'moulins'
|
||||
],
|
||||
nouvelleaquitaine: [
|
||||
'bordeaux', 'limoges', 'poitiers', 'la rochelle', 'bayonne', 'pau',
|
||||
'angouleme', 'perigueux', 'agen', 'niort', 'brive la gaillarde', 'dax',
|
||||
'hendaye', 'saintes', 'arcachon'
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Calcule la région la plus probable selon les arrêts desservis et le terminus
|
||||
*/
|
||||
function detectRegionByRouteScore(routeText) {
|
||||
if (!routeText) return null;
|
||||
const normalized = ` ${normalize(routeText)} `;
|
||||
|
||||
let bestRegion = null;
|
||||
let maxScore = 0;
|
||||
|
||||
for (const [regionKey, stations] of Object.entries(REGIONAL_STATIONS)) {
|
||||
let score = 0;
|
||||
for (const station of stations) {
|
||||
const stationNorm = ` ${normalize(station)} `;
|
||||
if (normalized.includes(stationNorm)) {
|
||||
score++;
|
||||
}
|
||||
}
|
||||
if (score > maxScore) {
|
||||
maxScore = score;
|
||||
bestRegion = regionKey;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxScore > 0 && bestRegion) {
|
||||
switch (bestRegion) {
|
||||
case 'lio': return BRANDS.LIO;
|
||||
case 'remi': return BRANDS.REMI;
|
||||
case 'mobigo': return BRANDS.MOBIGO;
|
||||
case 'zou': return BRANDS.ZOU;
|
||||
case 'fluo': return BRANDS.FLUO;
|
||||
case 'aleop': return BRANDS.ALEOP;
|
||||
case 'breizhgo': return BRANDS.BREIZHGO;
|
||||
case 'nomad': return BRANDS.NOMAD;
|
||||
case 'hautsdefrance': return BRANDS.HAUTS_DE_FRANCE;
|
||||
case 'auvergerhonealpes': return BRANDS.AUVERGNE_RHONE_ALPES;
|
||||
case 'nouvelleaquitaine': return BRANDS.NOUVELLE_AQUITAINE;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fonction centrale de classification d'un train à partir de ses données SNCF
|
||||
* @param {Object|string} trainOrType - Objet horaire ou type brut
|
||||
* @param {string} [operatorParam] - Opérateur ou transporteur optionnel
|
||||
* @param {string} [numParam] - Numéro de train optionnel
|
||||
* @returns {Object} Résultat complet de classification
|
||||
*/
|
||||
export function classifyTrain(trainOrType, operatorParam = '', numParam = '') {
|
||||
let horaire = null;
|
||||
let rawType = '';
|
||||
let opRaw = operatorParam || '';
|
||||
let numRaw = numParam || '';
|
||||
|
||||
if (trainOrType && typeof trainOrType === 'object') {
|
||||
horaire = trainOrType;
|
||||
rawType = horaire.type_train || horaire.type || horaire.train_type || horaire.commercial_mode || horaire.mode || '';
|
||||
opRaw = horaire.operator || horaire.op || horaire.transporteur || horaire.carrier || opRaw;
|
||||
numRaw = horaire.numero_train || horaire.numero || horaire.number || horaire.num || horaire.trip_short_name || numRaw;
|
||||
} else {
|
||||
rawType = String(trainOrType || '');
|
||||
}
|
||||
|
||||
const numTrain = extractTrainDigits(numRaw);
|
||||
const numInt = parseInt(numTrain, 10) || 0;
|
||||
const tripId = horaire ? String(horaire.trip_id || '') : '';
|
||||
const isSubstitution = Boolean(horaire && (horaire.is_substitution || horaire.is_sub));
|
||||
|
||||
const origName = horaire ? (horaire.gare_depart_nom || horaire.orig || horaire.origin || '') : '';
|
||||
const destName = horaire ? (horaire.gare_arrivee_nom || horaire.dest || horaire.destination || '') : '';
|
||||
const stopsText = Array.isArray(horaire?.stops) ? horaire.stops.map(s => (s.nom || s.gare_nom || s.name || '')).join(' ') : '';
|
||||
const fullRouteText = `${origName} ${destName} ${stopsText}`;
|
||||
const routeNormalized = normalize(fullRouteText);
|
||||
|
||||
const typeNorm = normalize(rawType);
|
||||
const opNorm = normalize(opRaw);
|
||||
const combined = `${typeNorm} ${opNorm}`.trim();
|
||||
|
||||
// Helper pour créer le résultat enrichi
|
||||
const buildResult = (brand, customProps = {}) => ({
|
||||
...brand,
|
||||
numTrain,
|
||||
rawType,
|
||||
rawOperator: opRaw,
|
||||
...customProps
|
||||
});
|
||||
|
||||
// =========================================================================
|
||||
// 1. SERVICES AUTOCAR / CAR TER / BUS DE SUBSTITUTION
|
||||
// =========================================================================
|
||||
if (
|
||||
isSubstitution ||
|
||||
isCarTrainNumber(numTrain) ||
|
||||
combined.includes('autocar') ||
|
||||
combined.includes('carter') ||
|
||||
combined.includes('substitution') ||
|
||||
combined === 'car' ||
|
||||
combined === 'bus'
|
||||
) {
|
||||
return buildResult(BRANDS.AUTOCAR);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 2. TGV LYRIA (Paris - Suisse : Genève, Lausanne, Zurich, Bâle)
|
||||
// =========================================================================
|
||||
if (
|
||||
combined.includes('lyria') ||
|
||||
tripId.includes(':LYR:FR') ||
|
||||
(numInt >= 9200 && numInt <= 9299) ||
|
||||
(numInt >= 9750 && numInt <= 9799)
|
||||
) {
|
||||
return buildResult(BRANDS.LYRIA);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 3. OUIGO TRAIN CLASSIQUE (4000-4399 ou 8040-8099, Paris Austerlitz/Bercy)
|
||||
// =========================================================================
|
||||
const isOuigoClassique = (
|
||||
combined.includes('ouigoclassique') ||
|
||||
combined.includes('trainclassique') ||
|
||||
combined.includes('classique') ||
|
||||
(combined.includes('ouigo') && ((numInt >= 4000 && numInt <= 4399) || (numInt >= 8040 && numInt <= 8099))) ||
|
||||
(tripId.includes(':OGO:FR') && ((numInt >= 4000 && numInt <= 4399) || (numInt >= 8040 && numInt <= 8099)))
|
||||
);
|
||||
if (isOuigoClassique) {
|
||||
return buildResult(BRANDS.OUIGO_CLASSIQUE);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 4. OUIGO (GRANDE VITESSE)
|
||||
// =========================================================================
|
||||
if (
|
||||
combined.includes('ouigo') ||
|
||||
tripId.includes(':OGO:FR') ||
|
||||
(numInt >= 7600 && numInt <= 7999)
|
||||
) {
|
||||
return buildResult(BRANDS.OUIGO_GV);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 5. INTERCITÉS DE NUIT (Lunéa)
|
||||
// =========================================================================
|
||||
if (
|
||||
combined.includes('denuit') ||
|
||||
combined.includes('nuit') ||
|
||||
combined.includes('lunea') ||
|
||||
tripId.includes(':ICN:FR') ||
|
||||
(numInt >= 3690 && numInt <= 3799) ||
|
||||
(numInt >= 3950 && numInt <= 3999) ||
|
||||
(numInt >= 5700 && numInt <= 5799)
|
||||
) {
|
||||
return buildResult(BRANDS.INTERCITES_NUIT);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 6. INTERCITÉS (Trains d'Équilibre du Territoire de jour)
|
||||
// =========================================================================
|
||||
if (
|
||||
combined.includes('intercites') ||
|
||||
combined === 'ic' ||
|
||||
combined.startsWith('ic ') ||
|
||||
tripId.includes(':IC:FR') ||
|
||||
(numInt >= 3000 && numInt <= 3949) ||
|
||||
(numInt >= 4400 && numInt <= 4999)
|
||||
) {
|
||||
return buildResult(BRANDS.INTERCITES);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 7. EUROSTAR & THALYS
|
||||
// =========================================================================
|
||||
const isEurostarOrThalys = (
|
||||
combined.includes('eurostar') ||
|
||||
combined.includes('thalys') ||
|
||||
(tripId.includes(':TRN:FR') && (routeNormalized.includes('bruxelles') || routeNormalized.includes('london') || routeNormalized.includes('amsterdam') || routeNormalized.includes('koln'))) ||
|
||||
((numInt >= 60 && numInt <= 99) && (routeNormalized.includes('bruxelles') || routeNormalized.includes('nord'))) ||
|
||||
(numInt >= 9000 && numInt <= 9499 && (routeNormalized.includes('bruxelles') || routeNormalized.includes('london') || routeNormalized.includes('amsterdam')))
|
||||
);
|
||||
if (isEurostarOrThalys) {
|
||||
if (combined.includes('thalys')) {
|
||||
return buildResult(BRANDS.THALYS);
|
||||
}
|
||||
return buildResult(BRANDS.EUROSTAR);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 8. FRECCIAROSSA / TRENITALIA (Paris Lyon - Lyon - Milan)
|
||||
// =========================================================================
|
||||
if (
|
||||
combined.includes('frecciarossa') ||
|
||||
combined.includes('freccia') ||
|
||||
combined.includes('trenitalia') ||
|
||||
(numInt >= 6640 && numInt <= 6670)
|
||||
) {
|
||||
return buildResult(BRANDS.FRECCIAROSSA);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 9. RENFE AVE (Marseille / Lyon - Madrid / Barcelone)
|
||||
// =========================================================================
|
||||
if (
|
||||
combined.includes('renfe') ||
|
||||
combined.includes('ave') ||
|
||||
[9724, 9725, 9731, 9732].includes(numInt)
|
||||
) {
|
||||
return buildResult(BRANDS.RENFE_AVE);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 10. ICE / DB (Paris Est - Allemagne)
|
||||
// =========================================================================
|
||||
if (
|
||||
combined.includes('ice') ||
|
||||
combined === 'db' ||
|
||||
tripId.includes(':ICE:FR') ||
|
||||
(numInt >= 9550 && numInt <= 9599)
|
||||
) {
|
||||
return buildResult(BRANDS.ICE);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 11. TGV INOUI & TGV GÉNÉRIQUE
|
||||
// =========================================================================
|
||||
if (
|
||||
combined.includes('inoui') ||
|
||||
combined.includes('tgvinoui') ||
|
||||
tripId.includes(':OUI:FR') ||
|
||||
combined.includes('tgv')
|
||||
) {
|
||||
return buildResult(BRANDS.INOUi);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 12. TRAM-TRAIN
|
||||
// =========================================================================
|
||||
if (
|
||||
combined.includes('tramtrain') ||
|
||||
combined.includes('tram-train') ||
|
||||
tripId.includes(':TT:FR')
|
||||
) {
|
||||
return buildResult(BRANDS.TRAMTRAIN);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 13. TERGV
|
||||
// =========================================================================
|
||||
if (combined.includes('tergv') || combined.includes('ter-gv')) {
|
||||
return buildResult(BRANDS.HAUTS_DE_FRANCE, { typeLabel: 'TERGV', quaiLabel: 'TERGV' });
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 14. OPÉRATEURS SUISSE, BELGE, LUXEMBOURGEOIS
|
||||
// =========================================================================
|
||||
if (combined.includes('sbb') || combined.includes('cff') || combined.includes('ffs')) {
|
||||
return buildResult(BRANDS.SBB);
|
||||
}
|
||||
if (combined.includes('sncb') || combined.includes('nmbs')) {
|
||||
return buildResult(BRANDS.SNCB);
|
||||
}
|
||||
if (combined.includes('cfl')) {
|
||||
return buildResult(BRANDS.CFL);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 15. TER RÉGIONAUX - DÉTECTION ROBUSTE PAR PALIER
|
||||
// =========================================================================
|
||||
|
||||
// Palier A : Mots-clés régionaux explicites dans l'opérateur ou type
|
||||
if (combined.includes('lio') || combined.includes('occitanie') || combined.includes('languedoc') || combined.includes('midipyrenees')) {
|
||||
return buildResult(BRANDS.LIO);
|
||||
}
|
||||
if (combined.includes('mobigo') || combined.includes('bourgogne') || combined.includes('franchecomte')) {
|
||||
return buildResult(BRANDS.MOBIGO);
|
||||
}
|
||||
if (combined.includes('zou') || combined.includes('paca') || combined.includes('ler')) {
|
||||
return buildResult(BRANDS.ZOU);
|
||||
}
|
||||
if (combined.includes('fluo') || combined.includes('grandest') || combined.includes('alsace') || combined.includes('lorraine') || combined.includes('metrolor')) {
|
||||
return buildResult(BRANDS.FLUO);
|
||||
}
|
||||
if (combined.includes('aleop') || combined.includes('paysdelaloire')) {
|
||||
return buildResult(BRANDS.ALEOP);
|
||||
}
|
||||
if (combined.includes('breizh') || combined.includes('bretagne')) {
|
||||
return buildResult(BRANDS.BREIZHGO);
|
||||
}
|
||||
if (combined.includes('nomad') || combined.includes('normandie')) {
|
||||
return buildResult(BRANDS.NOMAD);
|
||||
}
|
||||
if (combined.includes('remi') || combined.includes('centrevaldeloire')) {
|
||||
return buildResult(BRANDS.REMI);
|
||||
}
|
||||
if (combined.includes('hautsdefrance') || combined.includes('nordpasdecalais') || combined.includes('picardie')) {
|
||||
return buildResult(BRANDS.HAUTS_DE_FRANCE);
|
||||
}
|
||||
if (combined.includes('auvergerhonealpes') || combined.includes('rhonealpes') || combined.includes('auvergne')) {
|
||||
return buildResult(BRANDS.AUVERGNE_RHONE_ALPES);
|
||||
}
|
||||
if (combined.includes('nouvelleaquitaine') || combined.includes('aquitaine') || combined.includes('poitoucharentes') || combined.includes('limousin')) {
|
||||
return buildResult(BRANDS.NOUVELLE_AQUITAINE);
|
||||
}
|
||||
|
||||
// Palier B : Plan de numérotation SNCF (Strict & Déterministe)
|
||||
const regionByNum = getRegionByTrainNumber(numTrain);
|
||||
if (regionByNum) {
|
||||
return buildResult(regionByNum);
|
||||
}
|
||||
|
||||
// Palier C : Analyse géographique par score d'arrêts (si train hors numérotation standard)
|
||||
const regionByRoute = detectRegionByRouteScore(fullRouteText);
|
||||
if (regionByRoute) {
|
||||
return buildResult(regionByRoute);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 16. TER STANDARD (Fallback)
|
||||
// =========================================================================
|
||||
if (combined.includes('ter')) {
|
||||
return buildResult(BRANDS.TER_GENERIC);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 17. SNCF VOYAGEURS (Fallback par défaut)
|
||||
// =========================================================================
|
||||
return buildResult(BRANDS.SNCF_GENERIC, {
|
||||
typeLabel: rawType || 'SNCF',
|
||||
quaiLabel: rawType || 'SNCF'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface pour les afficheurs de Quai classiques (ClassiquesDepartsQuais & ClassiquesArriveesQuais)
|
||||
* @param {Object|string} trainTypeOrHoraire
|
||||
* @param {string} [operator]
|
||||
* @param {boolean} [isDeparture=true]
|
||||
* @param {string} [numTrainOverride]
|
||||
* @returns {{ logo: string, label: string, showVoyageursText: boolean, isTgv: boolean, classification: Object }}
|
||||
*/
|
||||
export function getTrainBrand(trainTypeOrHoraire = '', operator = '', isDeparture = true, numTrainOverride = '') {
|
||||
const c = classifyTrain(trainTypeOrHoraire, operator, numTrainOverride);
|
||||
|
||||
// Pour les trains sans marque spécifique :
|
||||
if (c.id === 'sncf' || c.id === 'ter') {
|
||||
if (isDeparture) {
|
||||
return {
|
||||
logo: BRANDS.SNCF_GENERIC.quaiLogo,
|
||||
label: c.quaiLabel || 'SNCF',
|
||||
showVoyageursText: true,
|
||||
isTgv: Boolean(c.isTgv),
|
||||
classification: c
|
||||
};
|
||||
}
|
||||
return {
|
||||
logo: BRANDS.TER_GENERIC.quaiLogo,
|
||||
label: c.quaiLabel || 'TER',
|
||||
showVoyageursText: false,
|
||||
isTgv: Boolean(c.isTgv),
|
||||
classification: c
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
logo: c.quaiLogo,
|
||||
label: c.quaiLabel,
|
||||
showVoyageursText: Boolean(c.showVoyageursText),
|
||||
isTgv: Boolean(c.isTgv),
|
||||
classification: c
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface pour les afficheurs Hall classiques (ClassiquesDeparts & ClassiquesArrivees)
|
||||
* @param {Object} horaire
|
||||
* @returns {{ logoSrc: string, typeLabel: string, numTrain: string, isTgv: boolean, brand: Object, classification: Object }}
|
||||
*/
|
||||
export function getTrainLogoAndMeta(horaire) {
|
||||
if (!horaire) {
|
||||
return {
|
||||
logoSrc: BRANDS.TER_GENERIC.hallLogo,
|
||||
typeLabel: 'TER',
|
||||
numTrain: '',
|
||||
isTgv: false,
|
||||
brand: getTrainBrand(),
|
||||
classification: BRANDS.TER_GENERIC
|
||||
};
|
||||
}
|
||||
|
||||
const c = classifyTrain(horaire);
|
||||
const brand = getTrainBrand(horaire, '', true);
|
||||
|
||||
return {
|
||||
logoSrc: c.hallLogo,
|
||||
typeLabel: c.typeLabel,
|
||||
numTrain: c.numTrain,
|
||||
isTgv: Boolean(c.isTgv),
|
||||
brand,
|
||||
classification: c
|
||||
};
|
||||
}
|
||||
@@ -180,7 +180,7 @@ export function getTrainLogoAndMeta(horaire) {
|
||||
} else if (opNorm.includes('breizhgo')) {
|
||||
typeLabel = 'BREIZHGO';
|
||||
} else if (opNorm.includes('hautsdefrance')) {
|
||||
typeLabel = 'HAUTS-DE-FRANCE';
|
||||
typeLabel = 'TER HDF';
|
||||
} else if (opNorm.includes('lio')) {
|
||||
typeLabel = 'LIÒ';
|
||||
} else if (opNorm.includes('zou')) {
|
||||
@@ -199,14 +199,48 @@ export function getTrainLogoAndMeta(horaire) {
|
||||
typeLabel = 'TER';
|
||||
}
|
||||
|
||||
// Spécificité régionale Bourgogne-Franche-Comté : TER commençant par 89xxxx ou 84xxxx -> MOBIGO
|
||||
if (typeLabel === 'TER' && (numTrain.startsWith('89') || numTrain.startsWith('84'))) {
|
||||
typeLabel = 'MOBIGO';
|
||||
if (!matchedLogo || matchedLogo.file === 'logo-ter.svg' || matchedLogo.file === 'logo-sncf.svg') {
|
||||
matchedLogo = logoLookup.get('mobigo') || matchedLogo;
|
||||
// Application du plan de numérotation déterministe TER
|
||||
if ((typeLabel === 'TER' || typeLabel === 'AUTOCAR' || typeLabel === 'Car TER') && numTrain) {
|
||||
const cleanNum = numTrain.replace(/\D/g, '');
|
||||
let matchedBrandSlug = null;
|
||||
let matchedBrandLabel = null;
|
||||
|
||||
if (cleanNum.length >= 4) {
|
||||
const p3 = parseInt(cleanNum.substring(0, 3), 10);
|
||||
const p4 = parseInt(cleanNum.substring(0, 4), 10);
|
||||
|
||||
if ((p3 >= 830 && p3 <= 840) || (p3 >= 160 && p3 <= 162)) {
|
||||
matchedBrandSlug = 'fluo'; matchedBrandLabel = 'FLUO';
|
||||
} else if ((p3 >= 841 && p3 <= 849) || p3 === 163 || p3 === 164) {
|
||||
matchedBrandSlug = 'hautsdefrance'; matchedBrandLabel = 'TER HDF';
|
||||
} else if ((p3 >= 850 && p3 <= 853) || p3 === 165) {
|
||||
matchedBrandSlug = 'nomad'; matchedBrandLabel = 'NOMAD';
|
||||
} else if ((p3 >= 854 && p3 <= 856) || (p4 >= 1660 && p4 <= 1664)) {
|
||||
matchedBrandSlug = 'breizhgo'; matchedBrandLabel = 'BREIZHGO';
|
||||
} else if ((p3 >= 857 && p3 <= 859) || (p4 >= 1665 && p4 <= 1674)) {
|
||||
matchedBrandSlug = 'aleop'; matchedBrandLabel = 'ALÉOP';
|
||||
} else if ((p3 >= 860 && p3 <= 862) || (p4 >= 1675 && p4 <= 1684)) {
|
||||
matchedBrandSlug = 'remi'; matchedBrandLabel = 'RÉMI';
|
||||
} else if ((p3 >= 863 && p3 <= 869) || (p4 >= 1685 && p4 <= 1709)) {
|
||||
matchedBrandSlug = 'teraquitaine'; matchedBrandLabel = 'TER NOUVELLE-AQUITAINE';
|
||||
} else if ((p3 >= 870 && p3 <= 872) || (p3 >= 876 && p3 <= 878) || (p4 >= 1710 && p4 <= 1719) || (p4 >= 1730 && p4 <= 1734)) {
|
||||
matchedBrandSlug = 'lio'; matchedBrandLabel = 'liO';
|
||||
} else if ((p3 >= 873 && p3 <= 875) || (p3 >= 882 && p3 <= 890) || (p4 >= 1720 && p4 <= 1729) || (p4 >= 1750 && p4 <= 1774) || (p4 >= 1790 && p4 <= 1799)) {
|
||||
matchedBrandSlug = 'ter-rhone-alpes'; matchedBrandLabel = 'TER AUVERGNE-RHÔNE-ALPES';
|
||||
} else if ((p3 >= 879 && p3 <= 881) || (p4 >= 1735 && p4 <= 1749)) {
|
||||
matchedBrandSlug = 'zou'; matchedBrandLabel = 'ZOU !';
|
||||
} else if ((p3 >= 891 && p3 <= 895) || (p4 >= 1775 && p4 <= 1789)) {
|
||||
matchedBrandSlug = 'mobigo'; matchedBrandLabel = 'MOBIGO';
|
||||
}
|
||||
|
||||
if (matchedBrandSlug && matchedBrandLabel) {
|
||||
typeLabel = matchedBrandLabel;
|
||||
if (!matchedLogo || matchedLogo.file === 'logo-ter.svg' || matchedLogo.file === 'logo-sncf.svg') {
|
||||
matchedLogo = logoLookup.get(matchedBrandSlug) || matchedLogo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const logoFile = (matchedLogo && matchedLogo.file) || 'logo-sncf.svg';
|
||||
const logoSrc = `/type/${logoFile}`;
|
||||
|
||||
|
||||
Reference in new issue
Block a user