mirror of
				https://github.com/public-transport/db-vendo-client.git
				synced 2025-10-31 08:06:33 +02:00 
			
		
		
		
	BVG profile
This commit is contained in:
		
							parent
							
								
									e20f65823b
								
							
						
					
					
						commit
						a3ad876bf5
					
				
					 4 changed files with 231 additions and 0 deletions
				
			
		
							
								
								
									
										37
									
								
								p/bvg/example.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								p/bvg/example.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| 'use strict' | ||||
| 
 | ||||
| const createClient = require('../..') | ||||
| const vbbProfile = require('.') | ||||
| 
 | ||||
| const client = createClient(vbbProfile, 'hafas-client-example') | ||||
| 
 | ||||
| // Hauptbahnhof to Charlottenburg
 | ||||
| client.journeys('900000003201', '900000024101', {results: 1, polylines: true}) | ||||
| // client.departures('900000013102', {duration: 1})
 | ||||
| // client.arrivals('900000013102', {duration: 10, stationLines: true})
 | ||||
| // client.locations('Alexanderplatz', {results: 2})
 | ||||
| // client.station('900000042101', {stationLines: true}) // Spichernstr
 | ||||
| // client.nearby({
 | ||||
| // 	type: 'location',
 | ||||
| // 	latitude: 52.5137344,
 | ||||
| // 	longitude: 13.4744798
 | ||||
| // }, {distance: 60})
 | ||||
| // client.radar({
 | ||||
| // 	north: 52.52411,
 | ||||
| // 	west: 13.41002,
 | ||||
| // 	south: 52.51942,
 | ||||
| // 	east: 13.41709
 | ||||
| // }, {results: 10})
 | ||||
| 
 | ||||
| // .then(([journey]) => {
 | ||||
| // 	const leg = journey.legs[0]
 | ||||
| // 	return client.trip(leg.id, leg.line.name, {polyline: true})
 | ||||
| // })
 | ||||
| 
 | ||||
| // .then(([journey]) => {
 | ||||
| // 	return client.refreshJourney(journey.refreshToken, {stopovers: true, remarks: true})
 | ||||
| // })
 | ||||
| .then((data) => { | ||||
| 	console.log(require('util').inspect(data, {depth: null})) | ||||
| }) | ||||
| .catch(console.error) | ||||
							
								
								
									
										112
									
								
								p/bvg/index.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								p/bvg/index.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,112 @@ | |||
| 'use strict' | ||||
| 
 | ||||
| const shorten = require('vbb-short-station-name') | ||||
| const {to12Digit, to9Digit} = require('vbb-translate-ids') | ||||
| const parseLineName = require('vbb-parse-line') | ||||
| const getStations = require('vbb-stations') | ||||
| 
 | ||||
| const _createParseLine = require('../../parse/line') | ||||
| const _parseLocation = require('../../parse/location') | ||||
| const _createParseDeparture = require('../../parse/departure') | ||||
| const _formatStation = require('../../format/station') | ||||
| 
 | ||||
| const products = require('./products') | ||||
| 
 | ||||
| const transformReqBody = (body) => { | ||||
| 	body.client = {type: 'IPA', id: 'BVG', name: 'FahrInfo', v: '4070700'} | ||||
| 	body.ext = 'BVG.1' | ||||
| 	body.ver = '1.15' // todo: 1.16 with `mic` and `mac` query params
 | ||||
| 	body.auth = {type: 'AID', aid: '1Rxs112shyHLatUX4fofnmdxK'} | ||||
| 
 | ||||
| 	return body | ||||
| } | ||||
| 
 | ||||
| const createParseLine = (profile, opt, data) => { | ||||
| 	const parseLine = _createParseLine(profile, opt, data) | ||||
| 
 | ||||
| 	const parseLineWithMoreDetails = (l) => { | ||||
| 		const res = parseLine(l) | ||||
| 
 | ||||
| 		res.name = l.name.replace(/^(bus|tram)\s+/i, '') | ||||
| 		const details = parseLineName(res.name) | ||||
| 		res.symbol = details.symbol | ||||
| 		res.nr = details.nr | ||||
| 		res.metro = details.metro | ||||
| 		res.express = details.express | ||||
| 		res.night = details.night | ||||
| 
 | ||||
| 		return res | ||||
| 	} | ||||
| 	return parseLineWithMoreDetails | ||||
| } | ||||
| 
 | ||||
| const parseLocation = (profile, opt, data, l) => { | ||||
| 	const res = _parseLocation(profile, opt, data, l) | ||||
| 
 | ||||
| 	if (res.type === 'stop' || res.type === 'station') { | ||||
| 		res.name = shorten(res.name) | ||||
| 		res.id = to12Digit(res.id) | ||||
| 		if (!res.location.latitude || !res.location.longitude) { | ||||
| 			const [s] = getStations(res.id) | ||||
| 			if (s) Object.assign(res.location, s.location) | ||||
| 		} | ||||
| 	} | ||||
| 	return res | ||||
| } | ||||
| 
 | ||||
| const createParseDeparture = (profile, opt, data) => { | ||||
| 	const parseDeparture = _createParseDeparture(profile, opt, data) | ||||
| 
 | ||||
| 	const ringbahnClockwise = /^ringbahn s\s?41$/i | ||||
| 	const ringbahnAnticlockwise = /^ringbahn s\s?42$/i | ||||
| 	const parseDepartureRenameRingbahn = (j) => { | ||||
| 		const res = parseDeparture(j) | ||||
| 
 | ||||
| 		if (res.line && res.line.product === 'suburban') { | ||||
| 			const d = res.direction && res.direction.trim() | ||||
| 			if (ringbahnClockwise.test(d)) res.direction = 'Ringbahn S41 ⟳' | ||||
| 			else if (ringbahnAnticlockwise.test(d)) res.direction = 'Ringbahn S42 ⟲' | ||||
| 		} | ||||
| 
 | ||||
| 		return res | ||||
| 	} | ||||
| 
 | ||||
| 	return parseDepartureRenameRingbahn | ||||
| } | ||||
| 
 | ||||
| const validIBNR = /^\d+$/ | ||||
| const formatStation = (id) => { | ||||
| 	if ('string' !== typeof id) throw new Error('station ID must be a string.') | ||||
| 	const l = id.length | ||||
| 	if ((l !== 7 && l !== 9 && l !== 12) || !validIBNR.test(id)) { | ||||
| 		throw new Error('station ID must be a valid IBNR.') | ||||
| 	} | ||||
| 	// BVG has some 7-digit stations. We don't convert them to 12 digits,
 | ||||
| 	// because it only recognizes in the 7-digit format. see derhuerst/vbb-hafas#22
 | ||||
| 	if (l !== 7) id = to9Digit(id) | ||||
| 	return _formatStation(id) | ||||
| } | ||||
| 
 | ||||
| // todo: adapt/extend `vbb-parse-ticket` to support the BVG markup
 | ||||
| 
 | ||||
| const bvgProfile = { | ||||
| 	locale: 'de-DE', | ||||
| 	timezone: 'Europe/Berlin', | ||||
| 	endpoint: 'https://bvg-apps.hafas.de/bin/mgate.exe', | ||||
| 
 | ||||
| 	transformReqBody, | ||||
| 
 | ||||
| 	products, | ||||
| 
 | ||||
| 	parseStationName: shorten, | ||||
| 	parseLocation, | ||||
| 	parseLine: createParseLine, | ||||
| 	parseDeparture: createParseDeparture, | ||||
| 
 | ||||
| 	formatStation, | ||||
| 
 | ||||
| 	trip: true, | ||||
| 	radar: true | ||||
| } | ||||
| 
 | ||||
| module.exports = bvgProfile | ||||
							
								
								
									
										60
									
								
								p/bvg/products.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								p/bvg/products.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| 'use strict' | ||||
| 
 | ||||
| module.exports = [ | ||||
| 	{ | ||||
| 		id: 'suburban', | ||||
| 		mode: 'train', | ||||
| 		bitmasks: [1], | ||||
| 		name: 'S-Bahn', | ||||
| 		short: 'S', | ||||
| 		default: true | ||||
| 	}, | ||||
| 	{ | ||||
| 		id: 'subway', | ||||
| 		mode: 'train', | ||||
| 		bitmasks: [2], | ||||
| 		name: 'U-Bahn', | ||||
| 		short: 'U', | ||||
| 		default: true | ||||
| 	}, | ||||
| 	{ | ||||
| 		id: 'tram', | ||||
| 		mode: 'train', | ||||
| 		bitmasks: [4], | ||||
| 		name: 'Tram', | ||||
| 		short: 'T', | ||||
| 		default: true | ||||
| 	}, | ||||
| 	{ | ||||
| 		id: 'bus', | ||||
| 		mode: 'bus', | ||||
| 		bitmasks: [8], | ||||
| 		name: 'Bus', | ||||
| 		short: 'B', | ||||
| 		default: true | ||||
| 	}, | ||||
| 	{ | ||||
| 		id: 'ferry', | ||||
| 		mode: 'watercraft', | ||||
| 		bitmasks: [16], | ||||
| 		name: 'Fähre', | ||||
| 		short: 'F', | ||||
| 		default: true | ||||
| 	}, | ||||
| 	{ | ||||
| 		id: 'express', | ||||
| 		mode: 'train', | ||||
| 		bitmasks: [32], | ||||
| 		name: 'IC/ICE', | ||||
| 		short: 'E', | ||||
| 		default: true | ||||
| 	}, | ||||
| 	{ | ||||
| 		id: 'regional', | ||||
| 		mode: 'train', | ||||
| 		bitmasks: [64], | ||||
| 		name: 'RB/RE', | ||||
| 		short: 'R', | ||||
| 		default: true | ||||
| 	} | ||||
| ] | ||||
							
								
								
									
										22
									
								
								p/bvg/readme.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								p/bvg/readme.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| # VBB profile for `hafas-client` | ||||
| 
 | ||||
| [*Verkehrsverbund Berlin-Brandenburg (VBB)*](https://en.wikipedia.org/wiki/Verkehrsverbund_Berlin-Brandenburg) is a group of public transport companies, running the public transport network in [Berlin](https://en.wikipedia.org/wiki/Berlin). This profile adds *VBB*-specific customizations to `hafas-client`. Consider using [`vbb-hafas`](https://github.com/derhuerst/vbb-hafas#vbb-hafas), to always get the customized client right away. | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| ```js | ||||
| const createClient = require('hafas-client') | ||||
| const vbbProfile = require('hafas-client/p/vbb') | ||||
| 
 | ||||
| // create a client with VBB profile | ||||
| const client = createClient(vbbProfile) | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| ## Customisations | ||||
| 
 | ||||
| - parses *VBB*-specific products (such as *X-Bus*) | ||||
| - strips parts from station names that are unnecessary in the Berlin context | ||||
| - parses line names to give more information (e.g. "Is it an express bus?") | ||||
| - parses *VBB*-specific tickets | ||||
| - renames *Ringbahn* line names to contain `⟳` and `⟲` | ||||
		Loading…
	
	Add table
		
		Reference in a new issue