DB: parse Reisezentrum opening hours & station facilities

This commit is contained in:
Jannis R 2020-02-15 19:16:18 +00:00
parent d92eb154c2
commit 9e75f42346
No known key found for this signature in database
GPG key ID: 0FE83946296A88A5
2 changed files with 151 additions and 2 deletions

View file

@ -1,6 +1,9 @@
'use strict' 'use strict'
const trim = require('lodash/trim') const trim = require('lodash/trim')
const uniqBy = require('lodash/uniqBy')
const slugg = require('slugg')
const without = require('lodash/without')
const {parseHook} = require('../../lib/profile-hooks') const {parseHook} = require('../../lib/profile-hooks')
const _parseJourney = require('../../parse/journey') const _parseJourney = require('../../parse/journey')
@ -9,6 +12,7 @@ const _parseLine = require('../../parse/line')
const _parseArrival = require('../../parse/arrival') const _parseArrival = require('../../parse/arrival')
const _parseDeparture = require('../../parse/departure') const _parseDeparture = require('../../parse/departure')
const _parseHint = require('../../parse/hint') const _parseHint = require('../../parse/hint')
const _parseLocation = require('../../parse/location')
const _formatStation = require('../../format/station') const _formatStation = require('../../format/station')
const {bike} = require('../../format/filters') const {bike} = require('../../format/filters')
@ -23,12 +27,101 @@ const transformReqBody = (ctx, body) => {
body.client = {id: 'DB', v: '16040000', type: 'IPH', name: 'DB Navigator'} body.client = {id: 'DB', v: '16040000', type: 'IPH', name: 'DB Navigator'}
body.ext = 'DB.R19.04.a' body.ext = 'DB.R19.04.a'
body.ver = '1.16' body.ver = '1.15'
body.auth = {type: 'AID', aid: 'n91dB8Z77MLdoR0K'} body.auth = {type: 'AID', aid: 'n91dB8Z77MLdoR0K'}
return body return body
} }
const slices = (n, arr) => {
const initialState = {slices: [], count: Infinity}
return arr.reduce(({slices, count}, item) => {
if (count >= n) {
slices.push([item])
count = 1
} else {
slices[slices.length - 1].push(item)
count++
}
return {slices, count}
}, initialState).slices
}
const parseGrid = (g) => {
// todo: g.type, e.g. `S`
return {
title: g.title,
rows: slices(g.nCols, g.itemL.map(item => item.msgL[0]))
}
}
const ausstattungKeys = Object.assign(Object.create(null), {
'3-s-zentrale': '3SZentrale',
'parkplatze': 'parkingLots',
'fahrrad-stellplatze': 'bicycleParkingRacks',
'opnv-anbindung': 'localPublicTransport',
'wc': 'toilets',
'schliessfacher': 'lockers',
'reisebedarf': 'travelShop',
'stufenfreier-zugang': 'stepFreeAccess',
'ein-umsteigehilfe': 'boardingAid',
'taxi-am-bahnhof': 'taxis'
})
const parseAusstattungVal = (val) => {
val = val.toLowerCase()
return val === 'ja' ? true : (val === 'nein' ? false : val)
}
const parseAusstattungGrid = (g) => {
// filter duplicate hint rows
const rows = uniqBy(g.rows, ([key, val]) => key + ':' + val)
const res = {raw: rows}
for (let [key, val] of rows) {
key = ausstattungKeys[slugg(key)]
if (key) res[key] = parseAusstattungVal(val)
}
return res
}
const parseReisezentrumÖffnungszeiten = (g) => {
const res = {}
for (const [dayOfWeek, val] of g.rows) res[dayOfWeek] = val
res.raw = g.rows
return res
}
const parseLocWithDetails = ({parsed, common}, l) => {
if (!parsed) return parsed
if (parsed.type !== 'stop' && parsed.type !== 'station') return parsed
if (Array.isArray(l.gridL)) {
const resolveCell = cell => 'hint' in cell ? cell.hint.text : cell
const resolveCells = grid => ({
...grid,
rows: grid.rows.map(row => row.map(resolveCell))
})
let grids = l.gridL
.map(grid => parseGrid(grid, common))
.map(resolveCells)
const ausstattung = grids.find(g => slugg(g.title) === 'ausstattung')
if (ausstattung) {
parsed.facilities = parseAusstattungGrid(ausstattung)
}
const öffnungszeiten = grids.find(g => slugg(g.title) === 'offnungszeiten-reisezentrum')
if (öffnungszeiten) {
parsed.reisezentrumOpeningHours = parseReisezentrumÖffnungszeiten(öffnungszeiten)
}
grids = without(grids, ausstattung, öffnungszeiten)
if (grids.length > 0) parsed.grids = grids
}
return parsed
}
// https://www.bahn.de/p/view/service/buchung/auslastungsinformation.shtml // https://www.bahn.de/p/view/service/buchung/auslastungsinformation.shtml
const loadFactors = [] const loadFactors = []
loadFactors[1] = 'low-to-medium' loadFactors[1] = 'low-to-medium'
@ -324,6 +417,11 @@ const codesByText = Object.assign(Object.create(null), {
}) })
const parseHintByCode = ({parsed}, raw) => { const parseHintByCode = ({parsed}, raw) => {
// plain-text hints used e.g. for stop metadata
if (raw.type === 'K') {
return {type: 'hint', text: raw.txtN}
}
if (raw.type === 'A') { if (raw.type === 'A') {
const hint = hintsByCode[raw.code && raw.code.trim().toLowerCase()] const hint = hintsByCode[raw.code && raw.code.trim().toLowerCase()]
if (hint) { if (hint) {
@ -360,7 +458,7 @@ const dbProfile = {
products: products, products: products,
// todo: parseLocation parseLocation: parseHook(_parseLocation, parseLocWithDetails),
parseJourney: parseHook(_parseJourney, parseJourneyWithPrice), parseJourney: parseHook(_parseJourney, parseJourneyWithPrice),
parseJourneyLeg: parseHook(_parseJourneyLeg, parseJourneyLegWithLoadFactor), parseJourneyLeg: parseHook(_parseJourneyLeg, parseJourneyLegWithLoadFactor),
parseLine: parseHook(_parseLine, parseLineWithAdditionalName), parseLine: parseHook(_parseLine, parseLineWithAdditionalName),

View file

@ -19,6 +19,57 @@ const client = createClient(dbProfile, 'my-awesome-program')
- supports [their loyalty cards](https://en.wikipedia.org/wiki/Deutsche_Bahn#Tickets) with `journey()` - supports [their loyalty cards](https://en.wikipedia.org/wiki/Deutsche_Bahn#Tickets) with `journey()`
- parses *DB*-specific products (such as *InterCity-Express*) - parses *DB*-specific products (such as *InterCity-Express*)
- exposes the cheapest ticket price for a `journey` - exposes the cheapest ticket price for a `journey`
- parses [*DB*-specific station info](#additional-station-info)
### additional station info
With the `db` profile, `hafas-client` will return more station information whenever the endpoint provides it:
```js
{
type: 'station',
id: '8004585',
name: 'Oberstdorf',
// …
facilities: {
'3SZentrale': '089/13081055',
parkingLots: true,
bicycleParkingRacks: true,
localPublicTransport: true,
toilets: true,
lockers: true,
travelShop: true,
stepFreeAccess: true,
boardingAid: 'ja, um voranmeldung unter 01806 512 512* wird gebeten',
taxis: true
},
reisezentrumOpeningHours: {
Mo: '08:00-18:00',
Di: '08:00-18:00',
Mi: '08:00-18:00',
Do: '08:00-18:00',
Fr: '08:00-18:00',
Sa: '09:00-14:00',
So: '09:00-14:00'
},
// …
stops: [{
type: 'stop',
id: '965503',
name: 'Busbahnhof, Oberstdorf',
// …
reisezentrumOpeningHours: {
Mo: '08:00-18:00',
Di: '08:00-18:00',
Mi: '08:00-18:00',
Do: '08:00-18:00',
Fr: '08:00-18:00',
Sa: '09:00-14:00',
So: '09:00-14:00'
}
}]
}
```
## Using the `loyaltyCard` option ## Using the `loyaltyCard` option