From a60083f8d19b35042ba0e9b2544fed53708eef49 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Wed, 16 Nov 2022 15:18:12 +0100 Subject: [PATCH] =?UTF-8?q?parse=20trip.scheduledDays=20=E2=9C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.js | 3 +- lib/default-profile.js | 2 + parse/journey.js | 43 ++--------------- parse/scheduled-days.js | 43 +++++++++++++++++ parse/trip.js | 16 ++++++- test/bvg-trip-with-occupancy.js | 1 + test/fixtures/bvg-trip-with-occupancy.js | 60 ++++++++++++++++++++++++ 7 files changed, 126 insertions(+), 42 deletions(-) create mode 100644 parse/scheduled-days.js diff --git a/index.js b/index.js index bddf2bdc..dd60c2f9 100644 --- a/index.js +++ b/index.js @@ -490,7 +490,8 @@ const createClient = (profile, userAgent, opt = {}) => { polyline: false, // return a track shape? subStops: true, // parse & expose sub-stops of stations? entrances: true, // parse & expose entrances of stops/stations? - remarks: true // parse & expose hints & warnings? + remarks: true, // parse & expose hints & warnings? + scheduledDays: false, // parse & expose dates trip is valid on? }, opt) const req = profile.formatTripReq({profile, opt}, id, lineName) diff --git a/lib/default-profile.js b/lib/default-profile.js index f4cd7406..a0ed5f11 100644 --- a/lib/default-profile.js +++ b/lib/default-profile.js @@ -19,6 +19,7 @@ const parseProductsBitmask = require('../parse/products-bitmask') const parseIcon = require('../parse/icon') const parseWhen = require('../parse/when') const parsePrognosisType = require('../parse/prognosis-type') +const parseScheduledDays = require('../parse/scheduled-days') const parseDeparture = require('../parse/departure') const parseArrival = require('../parse/arrival') const parseTrip = require('../parse/trip') @@ -85,6 +86,7 @@ const defaultProfile = { parseIcon, parseWhen, parsePrognosisType, + parseScheduledDays, parseDeparture, parseArrival, parseTrip, diff --git a/parse/journey.js b/parse/journey.js index 9736f75e..13292c5c 100644 --- a/parse/journey.js +++ b/parse/journey.js @@ -1,40 +1,7 @@ 'use strict' -const {DateTime} = require('luxon') const findRemarks = require('./find-remarks') -// todo: DRY with parse/date-time.js -const parseDate = (date) => { - const res = { - year: parseInt(date.substr(-8, 4)), - month: parseInt(date.substr(-4, 2)), - day: parseInt(date.substr(-2, 2)), - } - if (!Number.isInteger(res.year) || !Number.isInteger(res.month) || !Number.isInteger(res.day)) { - throw new Error('invalid date format: ' + date) - } - return res -} - -const parseScheduledDays = (sDaysB, fpB, fpE, profile) => { - sDaysB = Buffer.from(sDaysB, 'hex') - const res = Object.create(null) - - const _fpB = parseDate(fpB) - let d = DateTime.fromObject({ - zone: profile.timezone, locale: profile.locale, - year: _fpB.year, month: _fpB.month, day: _fpB.day, - hour: 0, minute: 0, second: 0, millisecond: 0 - }) - for (let b = 0; b < sDaysB.length; b++) { - for (let i = 0; i < 8; i++) { - res[d.toISODate()] = (sDaysB[b] & Math.pow(2, 7 - i)) > 0 - d = d.plus({days: 1}) - } - } - return res -} - // todo: c.conSubscr (e.g. `F`) // todo: c.trfRes x vbb-parse-ticket // todo: c.sotRating, c.isSotCon, c.sotCtxt @@ -70,13 +37,9 @@ const parseJourney = (ctx, j) => { // j = raw jouney res.remarks = findRemarks(j.msgL).map(([remark]) => remark) } - if (opt.scheduledDays) { - // sDaysB is a bitmap mapping all days from fpB (first date of schedule) to fpE (last date in schedule). - const {sDaysB} = j.sDays - const {fpB, fpE} = ctx.res - if (sDaysB && fpB && fpE) { - res.scheduledDays = parseScheduledDays(sDaysB, fpB, fpE, profile) - } + if (opt.scheduledDays && j.sDays) { + // todo [breaking]: rename to scheduledDates + res.scheduledDays = profile.parseScheduledDays(ctx, j.sDays) } return res diff --git a/parse/scheduled-days.js b/parse/scheduled-days.js new file mode 100644 index 00000000..3b6e23c1 --- /dev/null +++ b/parse/scheduled-days.js @@ -0,0 +1,43 @@ +'use strict' + +const {DateTime} = require('luxon') + +// todo: DRY with parse/date-time.js +const parseDate = (date) => { + const res = { + year: parseInt(date.substr(-8, 4)), + month: parseInt(date.substr(-4, 2)), + day: parseInt(date.substr(-2, 2)), + } + if (!Number.isInteger(res.year) || !Number.isInteger(res.month) || !Number.isInteger(res.day)) { + throw new Error('invalid date format: ' + date) + } + return res +} + +const parseScheduledDays = (ctx, sDays) => { + const {profile} = ctx + + // sDaysB is a bitmap mapping all days from fpB (first date of schedule) to fpE (last date in schedule). + const {fpB, fpE} = ctx.res + if (!sDays.sDaysB || !fpB || !fpE) return null + + const sDaysB = Buffer.from(sDays.sDaysB, 'hex') + const res = Object.create(null) + + const _fpB = parseDate(fpB) + let d = DateTime.fromObject({ + zone: profile.timezone, locale: profile.locale, + year: _fpB.year, month: _fpB.month, day: _fpB.day, + hour: 0, minute: 0, second: 0, millisecond: 0 + }) + for (let b = 0; b < sDaysB.length; b++) { + for (let i = 0; i < 8; i++) { + res[d.toISODate()] = (sDaysB[b] & Math.pow(2, 7 - i)) > 0 + d = d.plus({days: 1}) + } + } + return res +} + +module.exports = parseScheduledDays diff --git a/parse/trip.js b/parse/trip.js index fb56f34d..797ed06a 100644 --- a/parse/trip.js +++ b/parse/trip.js @@ -5,7 +5,7 @@ const maxBy = require('lodash/maxBy') const last = require('lodash/last') const parseTrip = (ctx, t) => { // t = raw trip - const {profile, res} = ctx + const {profile, opt, res} = ctx // pretend the trip is a leg in a journey const fakeLeg = { @@ -29,6 +29,20 @@ const parseTrip = (ctx, t) => { // t = raw trip delete trip.tripId // todo [breaking]: delete trip.reachable + if (opt.scheduledDays) { + const nrOfStopovers = t.stopL.length + // trips seem to use sDaysL[], journeys use sDays + const sDaysL = Array.isArray(t.sDaysL) ? t.sDaysL : [] + const matchingSDays = sDaysL.filter((sDays) => { + return sDays.fLocIdx === 0 && sDays.tLocIdx === (nrOfStopovers - 1) + }) + + // if there are >1 sDays, we don't know how to interpret them + const sDays = matchingSDays.length === 1 ? matchingSDays[0] : null + // todo [breaking]: rename to scheduledDates + trip.scheduledDays = profile.parseScheduledDays(ctx, sDays) + } + if (res.planrtTS) { // todo [breaking]: remove here trip.realtimeDataUpdatedAt = parseInt(res.planrtTS) diff --git a/test/bvg-trip-with-occupancy.js b/test/bvg-trip-with-occupancy.js index 1c109541..011b3c02 100644 --- a/test/bvg-trip-with-occupancy.js +++ b/test/bvg-trip-with-occupancy.js @@ -16,6 +16,7 @@ const opt = { subStops: false, entrances: true, remarks: true, + scheduledDays: true, when: '2021-10-28T09:28:00+02:00', } diff --git a/test/fixtures/bvg-trip-with-occupancy.js b/test/fixtures/bvg-trip-with-occupancy.js index 43dad72b..a6d6fad2 100644 --- a/test/fixtures/bvg-trip-with-occupancy.js +++ b/test/fixtures/bvg-trip-with-occupancy.js @@ -44,6 +44,66 @@ module.exports = { } ], occupancy: 'medium', + + scheduledDays: { + '2021-10-22': true, + '2021-10-23': false, + '2021-10-24': false, + '2021-10-25': true, + '2021-10-26': true, + '2021-10-27': true, + '2021-10-28': true, + '2021-10-29': true, + '2021-10-30': false, + '2021-10-31': false, + '2021-11-01': true, + '2021-11-02': true, + '2021-11-03': true, + '2021-11-04': true, + '2021-11-05': true, + '2021-11-06': false, + '2021-11-07': false, + '2021-11-08': true, + '2021-11-09': true, + '2021-11-10': true, + '2021-11-11': true, + '2021-11-12': true, + '2021-11-13': false, + '2021-11-14': false, + '2021-11-15': true, + '2021-11-16': true, + '2021-11-17': true, + '2021-11-18': true, + '2021-11-19': true, + '2021-11-20': false, + '2021-11-21': false, + '2021-11-22': true, + '2021-11-23': true, + '2021-11-24': true, + '2021-11-25': true, + '2021-11-26': true, + '2021-11-27': false, + '2021-11-28': false, + '2021-11-29': true, + '2021-11-30': true, + '2021-12-01': true, + '2021-12-02': true, + '2021-12-03': true, + '2021-12-04': false, + '2021-12-05': false, + '2021-12-06': true, + '2021-12-07': true, + '2021-12-08': true, + '2021-12-09': true, + '2021-12-10': true, + '2021-12-11': false, + '2021-12-12': false, + '2021-12-13': false, + '2021-12-14': false, + '2021-12-15': false, + '2021-12-16': false, + }, + realtimeDataUpdatedAt: 1635406146, origin: {