mirror of
https://github.com/public-transport/db-vendo-client.git
synced 2025-02-23 07:09:35 +02:00
DB: parse Reisezentrum opening hours & station facilities
This commit is contained in:
parent
d92eb154c2
commit
9e75f42346
2 changed files with 151 additions and 2 deletions
102
p/db/index.js
102
p/db/index.js
|
@ -1,6 +1,9 @@
|
|||
'use strict'
|
||||
|
||||
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 _parseJourney = require('../../parse/journey')
|
||||
|
@ -9,6 +12,7 @@ const _parseLine = require('../../parse/line')
|
|||
const _parseArrival = require('../../parse/arrival')
|
||||
const _parseDeparture = require('../../parse/departure')
|
||||
const _parseHint = require('../../parse/hint')
|
||||
const _parseLocation = require('../../parse/location')
|
||||
const _formatStation = require('../../format/station')
|
||||
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.ext = 'DB.R19.04.a'
|
||||
body.ver = '1.16'
|
||||
body.ver = '1.15'
|
||||
body.auth = {type: 'AID', aid: 'n91dB8Z77MLdoR0K'}
|
||||
|
||||
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
|
||||
const loadFactors = []
|
||||
loadFactors[1] = 'low-to-medium'
|
||||
|
@ -324,6 +417,11 @@ const codesByText = Object.assign(Object.create(null), {
|
|||
})
|
||||
|
||||
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') {
|
||||
const hint = hintsByCode[raw.code && raw.code.trim().toLowerCase()]
|
||||
if (hint) {
|
||||
|
@ -360,7 +458,7 @@ const dbProfile = {
|
|||
|
||||
products: products,
|
||||
|
||||
// todo: parseLocation
|
||||
parseLocation: parseHook(_parseLocation, parseLocWithDetails),
|
||||
parseJourney: parseHook(_parseJourney, parseJourneyWithPrice),
|
||||
parseJourneyLeg: parseHook(_parseJourneyLeg, parseJourneyLegWithLoadFactor),
|
||||
parseLine: parseHook(_parseLine, parseLineWithAdditionalName),
|
||||
|
|
|
@ -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()`
|
||||
- parses *DB*-specific products (such as *InterCity-Express*)
|
||||
- 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
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue