Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kitinerary for openSUSE:Factory checked in at 2023-07-07 15:46:47 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kitinerary (Old) and /work/SRC/openSUSE:Factory/.kitinerary.new.23466 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kitinerary" Fri Jul 7 15:46:47 2023 rev:63 rq:1097278 version:23.04.3 Changes: -------- --- /work/SRC/openSUSE:Factory/kitinerary/kitinerary.changes 2023-06-09 20:36:44.642312518 +0200 +++ /work/SRC/openSUSE:Factory/.kitinerary.new.23466/kitinerary.changes 2023-07-07 15:47:16.984182625 +0200 @@ -1,0 +2,21 @@ +Tue Jul 4 10:19:52 UTC 2023 - Christophe Marin <christo...@krop.fr> + +- Update to 23.04.3 + * New bugfix release + * For more details please see: + * https://kde.org/announcements/gear/23.04.3/ +- Changes since 23.04.2: + * Use a faster regex for matching Grimaldi Line passenger data + * Add Color Line extractor script + * Support onepagebooking PDFs as well + * Expand the Fjord Line trigger expression to cover newer tickets + * Treat any sequence of * characters as RCT2 empty marker + * Accept also slightly larger ERA SSBv3 codes + * Simplify Trenitalia extractor + * Extract DJH membership card barcodes + * Fix extraction of multi-page Trenitalia tickets + * Improve handling of Flixbus train tickets + * Add additional sanity checks for ERA SSBv2 tickets + * Relax the SNCB barcode trigger pattern a bit + +------------------------------------------------------------------- Old: ---- kitinerary-23.04.2.tar.xz kitinerary-23.04.2.tar.xz.sig New: ---- kitinerary-23.04.3.tar.xz kitinerary-23.04.3.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kitinerary.spec ++++++ --- /var/tmp/diff_new_pack.8dhibP/_old 2023-07-07 15:47:18.304190489 +0200 +++ /var/tmp/diff_new_pack.8dhibP/_new 2023-07-07 15:47:18.316190560 +0200 @@ -19,7 +19,7 @@ %define libname libKPimItinerary5 %bcond_without released Name: kitinerary -Version: 23.04.2 +Version: 23.04.3 Release: 0 Summary: Data model and extraction system for travel reservations License: LGPL-2.1-or-later ++++++ kitinerary-23.04.2.tar.xz -> kitinerary-23.04.3.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/CMakeLists.txt new/kitinerary-23.04.3/CMakeLists.txt --- old/kitinerary-23.04.2/CMakeLists.txt 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/CMakeLists.txt 2023-07-04 07:16:41.000000000 +0200 @@ -3,7 +3,7 @@ # SPDX-License-Identifier: BSD-3-Clause cmake_minimum_required(VERSION 3.16 FATAL_ERROR) -set(PIM_VERSION "5.23.2") +set(PIM_VERSION "5.23.3") project(KItinerary VERSION ${PIM_VERSION}) set(KF_MIN_VERSION "5.91.0") @@ -48,8 +48,8 @@ find_package(SharedMimeInfo 1.3 REQUIRED) endif() -set(KMIME_VERSION "5.23.2") -set(PIM_PKPASS "5.23.2") +set(KMIME_VERSION "5.23.3") +set(PIM_PKPASS "5.23.3") find_package(KPim${KF_MAJOR_VERSION}Mime ${KMIME_VERSION} CONFIG REQUIRED) find_package(KPimPkPass ${PIM_PKPASS} CONFIG REQUIRED) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/po/zh_CN/kitinerary.po new/kitinerary-23.04.3/po/zh_CN/kitinerary.po --- old/kitinerary-23.04.2/po/zh_CN/kitinerary.po 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/po/zh_CN/kitinerary.po 2023-07-04 07:16:41.000000000 +0200 @@ -3,7 +3,7 @@ "Project-Id-Version: kdeorg\n" "Report-Msgid-Bugs-To: https://bugs.kde.org\n" "POT-Creation-Date: 2022-07-20 00:46+0000\n" -"PO-Revision-Date: 2023-05-22 14:03\n" +"PO-Revision-Date: 2023-07-03 11:40\n" "Last-Translator: \n" "Language-Team: Chinese Simplified\n" "Language: zh_CN\n" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/cli/org.kde.kitinerary-extractor.appdata.xml new/kitinerary-23.04.3/src/cli/org.kde.kitinerary-extractor.appdata.xml --- old/kitinerary-23.04.2/src/cli/org.kde.kitinerary-extractor.appdata.xml 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/src/cli/org.kde.kitinerary-extractor.appdata.xml 2023-07-04 07:16:41.000000000 +0200 @@ -116,9 +116,9 @@ <binary>kitinerary-extractor</binary> </provides> <releases> + <release version="5.23.3" date="2023-07-06"/> <release version="5.23.2" date="2023-06-08"/> <release version="5.23.1" date="2023-05-11"/> <release version="5.23.0" date="2023-04-20"/> - <release version="5.22.3" date="2023-03-02"/> </releases> </component> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/era/ssbv2ticket.cpp new/kitinerary-23.04.3/src/lib/era/ssbv2ticket.cpp --- old/kitinerary-23.04.2/src/lib/era/ssbv2ticket.cpp 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/src/lib/era/ssbv2ticket.cpp 2023-07-04 07:16:41.000000000 +0200 @@ -22,7 +22,17 @@ { if (maybeSSB(data)) { m_data = data; - } else { + + // additional sanity checking to catch the maybeSSB heuristic not being good enough + // trainNumber() > 99999 would also be an effective check, wouldn't it be for the Trenitalia + // deviations from the SSBv2 spec... + if (numberOfAdultPassengers() > 99 || numberOfChildPassengers() > 99) + { + m_data.clear(); + } + } + + if (m_data.isEmpty()) { qWarning() << "Trying to construct an SSB ticket from invalid data!"; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/era/ssbv3ticket.cpp new/kitinerary-23.04.3/src/lib/era/ssbv3ticket.cpp --- old/kitinerary-23.04.2/src/lib/era/ssbv3ticket.cpp 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/src/lib/era/ssbv3ticket.cpp 2023-07-04 07:16:41.000000000 +0200 @@ -13,7 +13,8 @@ using namespace KItinerary; enum { - SSBV3_DATA_SIZE = 114, + SSBV3_MIN_DATA_SIZE = 114, + SSBV3_MAX_DATA_SIZE = 122, SSBV3_CHAR_WIDTH = 6, SSBV3_VERSION = 3, }; @@ -48,7 +49,7 @@ bool SSBv3Ticket::maybeSSB(const QByteArray& data) { - if (data.size() != SSBV3_DATA_SIZE) { + if (data.size() < SSBV3_MIN_DATA_SIZE || data.size() > SSBV3_MAX_DATA_SIZE) { return false; } return (data.at(0) >> 4) == SSBV3_VERSION; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/scripts/colorline.js new/kitinerary-23.04.3/src/lib/scripts/colorline.js --- old/kitinerary-23.04.2/src/lib/scripts/colorline.js 1970-01-01 01:00:00.000000000 +0100 +++ new/kitinerary-23.04.3/src/lib/scripts/colorline.js 2023-07-04 07:16:41.000000000 +0200 @@ -0,0 +1,17 @@ +/* + SPDX-FileCopyrightText: 2023 Volker Krause <vkra...@kde.org> + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +function extractPdf(pdf) { + const text = pdf.text; + let res = JsonLd.newBoatReservation(); + res.reservationNumber = text.match(/Booking reference: (\S+)/)[1]; + res.underName.name = text.match(/Responsible: (.*)/)[1]; + const trip = text.match(/Departure: (.*) \S+ (\d\d\.\d\d\.\d{4} \d\d:\d\d) Arrival: (.*) \S+ (\d\d\.\d\d\.\d{4} \d\d:\d\d)/); + res.reservationFor.departureBoatTerminal.name = trip[1]; + res.reservationFor.departureTime = JsonLd.toDateTime(trip[2], 'dd.MM.yyyy hh:mm', 'en'); + res.reservationFor.arrivalBoatTerminal.name = trip[3]; + res.reservationFor.arrivalTime = JsonLd.toDateTime(trip[4], 'dd.MM.yyyy hh:mm', 'en'); + return res; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/scripts/colorline.json new/kitinerary-23.04.3/src/lib/scripts/colorline.json --- old/kitinerary-23.04.2/src/lib/scripts/colorline.json 1970-01-01 01:00:00.000000000 +0100 +++ new/kitinerary-23.04.3/src/lib/scripts/colorline.json 2023-07-04 07:16:41.000000000 +0200 @@ -0,0 +1,13 @@ +{ + "filter": [ + { + "field": "text", + "match": "^Color Line GmbH\\n", + "mimeType": "application/pdf", + "scope": "Current" + } + ], + "function": "extractPdf", + "mimeType": "application/pdf", + "script": "colorline.js" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/scripts/djh.js new/kitinerary-23.04.3/src/lib/scripts/djh.js --- old/kitinerary-23.04.2/src/lib/scripts/djh.js 1970-01-01 01:00:00.000000000 +0100 +++ new/kitinerary-23.04.3/src/lib/scripts/djh.js 2023-07-04 07:16:41.000000000 +0200 @@ -0,0 +1,23 @@ +/* + SPDX-FileCopyrightText: 2023 Volker Krause <vkra...@kde.org> + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +function parseMembershipCard(code) { + console.log(code); + const c = code.split(/;/); + let card = { + '@type': 'ProgramMembership', + programName: 'DJH Mitgliedskarte (' + c[10] + ')', + membershipNumber: c[0].substr(1), + member: { + '@type': 'Person', + givenName: c[2], + familyName: c[3], + }, + token: 'dataMatrix:' + code, + validFrom: JsonLd.toDateTime(c[12], 'dd.MM.yyyy?', 'de'), + validUntil: JsonLd.toDateTime(c[11], 'MM/yyyy', 'de'), + }; + return card; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/scripts/djh.json new/kitinerary-23.04.3/src/lib/scripts/djh.json --- old/kitinerary-23.04.2/src/lib/scripts/djh.json 1970-01-01 01:00:00.000000000 +0100 +++ new/kitinerary-23.04.3/src/lib/scripts/djh.json 2023-07-04 07:16:41.000000000 +0200 @@ -0,0 +1,12 @@ +{ + "filter": [ + { + "match": "^%\\d{3}-\\d{8} \\d{3};.*;\\d\\d/\\d{4};\\d\\d\\.\\d\\d\\.\\d{4}\\?$", + "mimeType": "text/plain", + "scope": "Current" + } + ], + "function": "parseMembershipCard", + "mimeType": "text/plain", + "script": "djh.js" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/scripts/extractors.qrc new/kitinerary-23.04.3/src/lib/scripts/extractors.qrc --- old/kitinerary-23.04.2/src/lib/scripts/extractors.qrc 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/src/lib/scripts/extractors.qrc 2023-07-04 07:16:41.000000000 +0200 @@ -53,12 +53,16 @@ <file>caesar-data.js</file> <file>chaos-communication-congress.json</file> <file>chaos-communication-congress.js</file> + <file>colorline.json</file> + <file>colorline.js</file> <file>czechrailways.json</file> <file>czechrailways.js</file> <file>deutschebahn.json</file> <file>deutschebahn.js</file> <file>dinnerbooking.json</file> <file>dinnerbooking.js</file> + <file>djh.json</file> + <file>djh.js</file> <file>drk-blutspendedienst.json</file> <file>drk-blutspendedienst.js</file> <file>easyairportparking.json</file> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/scripts/fjordline.json new/kitinerary-23.04.3/src/lib/scripts/fjordline.json --- old/kitinerary-23.04.2/src/lib/scripts/fjordline.json 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/src/lib/scripts/fjordline.json 2023-07-04 07:16:41.000000000 +0200 @@ -1,7 +1,7 @@ { "filter": [ { - "match": "^\\d{7}$", + "match": "^\\d{7,8}$", "mimeType": "text/plain", "scope": "Descendants" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/scripts/flixbus.js new/kitinerary-23.04.3/src/lib/scripts/flixbus.js --- old/kitinerary-23.04.2/src/lib/scripts/flixbus.js 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/src/lib/scripts/flixbus.js 2023-07-04 07:16:41.000000000 +0200 @@ -3,6 +3,16 @@ SPDX-License-Identifier: LGPL-2.0-or-later */ +// convert bus reservations to train reservations when needed +function fixTransportMode(res) { + if (res.reservationFor.departureBusStop.name.endsWith(" (FlixTrain)") && res.reservationFor.arrivalBusStop.name.endsWith(" (FlixTrain)")) { + res = JsonLd.busToTrainReservation(res); + res.reservationFor.departureStation.name = res.reservationFor.departureStation.name.substr(0, res.reservationFor.departureStation.name.length - 11); + res.reservationFor.arrivalStation.name = res.reservationFor.arrivalStation.name.substr(0, res.reservationFor.arrivalStation.name.length - 11); + } + return res; +} + function main(content, node) { // convert QR download links into the actual QR codes var res = node.result; @@ -11,11 +21,7 @@ res[i].reservedTicket.ticketToken = ticketToken.replace(/^https?:\/\/api\.(?:flixbus|meinfernbus)\..{2,3}\/qrcode\/(..)\//, "qrCode:https://shop.flixbus.$1/pdfqr/"); // their schema.org annotations also claim train trips are bus trips, fix that - if (res[i].reservationFor.departureBusStop.name.endsWith(" (FlixTrain)") && res[i].reservationFor.arrivalBusStop.name.endsWith(" (FlixTrain)")) { - res[i] = JsonLd.busToTrainReservation(res[i]); - res[i].reservationFor.departureStation.name = res[i].reservationFor.departureStation.name.substr(0, res[i].reservationFor.departureStation.name.length - 11); - res[i].reservationFor.arrivalStation.name = res[i].reservationFor.arrivalStation.name.substr(0, res[i].reservationFor.arrivalStation.name.length - 11); - } + res[i] = fixTransportMode(res[i]); } return res; } @@ -57,7 +63,7 @@ let reservations = []; while (true) { const times = timeColumn.substr(idxTime).match(/(\d\d:\d\d)\n([^:]*?\n)?([^:]*?\n)?(\d\d:\d\d)/); - const stations = stationColumn.substr(idxStations).match(/(.*)\n[î¤»î¥ î¥¯]+(.*)(?:\n|,\n +(.*)\n).*(?:Bus|Autobus) +(.*)\n.*(?:Direction|à destination de|Kierunek|richting|Richtung) (.*)\n(.*)\n(?:[î¤»î¥ î¥¯]+(.*?)(?:\n|,\n +(.*)\n))?/); + const stations = stationColumn.substr(idxStations).match(/(.*)\n[î¤»î¥ î¥¯]+(.*)(?:\n|,\n +(.*)\n)(?:î ©.*\n(?:.*\n)*)?.*(?:Bus|Autobus|Zug) +(.*)\n.*(?:Direction|à destination de|Kierunek|richting|Richtung) (.*)\n(.*)\n(?:[î¤»î¥ î¥¯]+(.*?)(?:\n|,\n +(.*)\n))?/); if (!times || !stations) { break; } @@ -79,7 +85,28 @@ res.reservationFor.arrivalBusStop.name = stations[6]; parseLocation(res.reservationFor.arrivalBusStop, stations[7], stations[8], links); - reservations.push(res); + reservations.push(fixTransportMode(res)); + } + + if (reservations.length > 1) // unclear how to match seats in that case + return reservations; + + const rightSide = page.textInRect(0.47, 0.0, 1.0, 0.5); + let idx = 0; + let personalizedReservations = []; + while (true) { + const pas = rightSide.substr(idx).match(/(\S+.*\S) +(?:(\d+) · )?(\d+[A-Z])\n/); + if (!pas) { + break; + } + idx += pas.index + pas[0].length; + for (res of reservations) { + let r = JsonLd.clone(res); + r.underName.name = pas[1]; + r.reservedTicket.ticketedSeat.seatNumber = pas[3]; + r.reservedTicket.ticketedSeat.seatSection = pas[2]; + personalizedReservations.push(r); + } } - return reservations; + return personalizedReservations.length ? personalizedReservations : reservations; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/scripts/grimaldi-lines.js new/kitinerary-23.04.3/src/lib/scripts/grimaldi-lines.js --- old/kitinerary-23.04.2/src/lib/scripts/grimaldi-lines.js 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/src/lib/scripts/grimaldi-lines.js 2023-07-04 07:16:41.000000000 +0200 @@ -18,7 +18,7 @@ let idx = 0; let reservations = [res]; while (true) { - const pas = text.substr(idx).match(/ +(.*?) +[MF] +\d\d-\d\d-\d{4}\n/); + const pas = text.substr(idx).match(/ +(\S.*\S) +[MF] +\d\d-\d\d-\d{4}\n/); if (!pas) break; idx += pas.index + pas[0].length; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/scripts/onepagebooking.js new/kitinerary-23.04.3/src/lib/scripts/onepagebooking.js --- old/kitinerary-23.04.2/src/lib/scripts/onepagebooking.js 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/src/lib/scripts/onepagebooking.js 2023-07-04 07:16:41.000000000 +0200 @@ -74,3 +74,25 @@ res.underName.name = pass.field['guestname'].value; return res; } + +function parsePdf(pdf, node, triggerNode) +{ + const page = pdf.pages[triggerNode.location]; + let res = JsonLd.newLodgingReservation(); + res.reservationNumber = page.text.match(/.*: ([A-Z0-9-]+)/)[1]; + const leftCol = page.textInRect(0.0, 0.2, 0.5, 1.0); + const dates = leftCol.match(/(\d\d\.\d\d.\d{4}).*(\d\d\.\d\d.\d{4})/); + const times = leftCol.match(/(\d\d\:\d\d).*(\d\d\:\d\d)/); + res.checkinTime = JsonLd.toDateTime(dates[1] + ' ' + times[1], 'dd.MM.yyyy hh:mm', 'de'); + res.checkoutTime = JsonLd.toDateTime(dates[2] + ' ' + times[2], 'dd.MM.yyyy hh:mm', 'de'); + const rightCol = page.textInRect(0.5, 0.2, 1.0, 1.0); + const addr = rightCol.match(/.*\n(.*)\n(.*)\n(.*)/); + res.reservationFor.name = addr[1]; + res.reservationFor.address.streetAddress = addr[2]; + res.reservationFor.address.addressLocality = addr[3]; + res.reservationFor.telephone = page.links[0].url.substr(4); + res.reservationFor.email = page.links[1].url.substr(7); + res.reservationFor.geo = JsonLd.toGeoCoordinates(page.links[2].url); + res.modifyReservationUrl = page.links[3].url; + return res; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/scripts/onepagebooking.json new/kitinerary-23.04.3/src/lib/scripts/onepagebooking.json --- old/kitinerary-23.04.2/src/lib/scripts/onepagebooking.json 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/src/lib/scripts/onepagebooking.json 2023-07-04 07:16:41.000000000 +0200 @@ -23,4 +23,16 @@ "function": "parsePkPass", "mimeType": "application/vnd.apple.pkpass", "script": "onepagebooking.js" +}, +{ + "filter": [ + { + "match": "^https://onepagebooking.com/", + "mimeType": "text/plain", + "scope": "Descendants" + } + ], + "function": "parsePdf", + "mimeType": "application/pdf", + "script": "onepagebooking.js" }] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/scripts/sncb.json new/kitinerary-23.04.3/src/lib/scripts/sncb.json --- old/kitinerary-23.04.2/src/lib/scripts/sncb.json 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/src/lib/scripts/sncb.json 2023-07-04 07:16:41.000000000 +0200 @@ -8,7 +8,7 @@ "scope": "Ancestors" }, { - "match": "^[A-Z][A-Z0-9]{14}$", + "match": "^[A-Z0-9][A-Z0-9-]{14}$", "mimeType": "text/plain", "scope": "Descendants" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/scripts/trenitalia.js new/kitinerary-23.04.3/src/lib/scripts/trenitalia.js --- old/kitinerary-23.04.2/src/lib/scripts/trenitalia.js 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/src/lib/scripts/trenitalia.js 2023-07-04 07:16:41.000000000 +0200 @@ -45,67 +45,61 @@ return res; } -function parsePdf(pdf, node) { - var reservations = new Array(); +function parsePdf(pdf, node, triggerNode) { + let reservations = []; + const page = pdf.pages[triggerNode.location]; + const text = page.text; + + var res = JsonLd.newTrainReservation(); + var pnr = text.match(/PNR: (\S+)/); + if (pnr) { + res.reservationNumber = pnr[1]; + } - for (var i = 0; i < pdf.pageCount; ++i) { - var page = pdf.pages[i]; - var text = page.text; - - var res = JsonLd.newTrainReservation(); - var pnr = text.match(/PNR: (\S+)/); - if (pnr) { - res.reservationNumber = pnr[1]; + const leftHeaderText = page.textInRect(0.0, 0.15, 0.33, 0.25); + const midHeaderText = page.textInRect(0.33, 0.15, 0.65, 0.25); + const rightHeaderText = page.textInRect(0.65, 0.15, 1.0, 0.25); + + const train = rightHeaderText.match(/(?:Train|Treno|Zug)(?:\/Train)?:[ \n](.*)\n/); + res.reservationFor.trainNumber = train[1]; + + const departure_time = leftHeaderText.match(/(\d{2}:\d{2}) - (\d{2}\/\d{2}\/\d{4})/) + const arrival_time = midHeaderText.match(/(\d{2}:\d{2}) - (\d{2}\/\d{2}\/\d{4})/) + res.reservationFor.departureTime = JsonLd.toDateTime(departure_time[2] + departure_time[1], "dd/MM/yyyyhh:mm", "it"); + res.reservationFor.arrivalTime = JsonLd.toDateTime(arrival_time[2] + arrival_time[1], "dd/MM/yyyyhh:mm", "it"); + + const dep = leftHeaderText.match(/(?:Stazione di Partenza|Departure station|Abfahrtsbahnhof|Gare de départ)(?:\/From)?\n+(.*)\n/); + res.reservationFor.departureStation.name = dep[1]; + const arr = midHeaderText.match(/(?:Stazione di Arrivo|Arrival station|Ankunft Bahnhof|Gare d'arrivée)(?:\/To)?\n+(.*)\n/); + res.reservationFor.arrivalStation.name = arr[1]; + + const barcodes = node.findChildNodes({ scope: "Descendants", mimeType: "internal/era-ssb", field: "issuerCode", match: "83" }).concat(node.findChildNodes({ scope: "Descendants", mimeType: "internal/uic9183", field: "carrierId", match: "83" })); + var offset = 0; + const passengerColumn = page.textInRect(0.0, 0.3, 0.27, 1.0); + for (let j = 0; j < barcodes.length; ++j) { + if (barcodes[j].location != triggerNode.location) { + continue; + } + let personalRes = JsonLd.clone(res); + var name = passengerColumn.substr(offset).match(/(?:Passenger Name|Nome Passeggero|Nom du Passager)(?:\/Passenger\n *name)?.*\n(?: .*\n)* *((?:\w+|\-\-).*?)(?: |\n)/); + offset += name.index + name[0].length; + if (name[1] !== "--") { + personalRes.underName.name = name[1]; + } else { + personalRes.underName.name = "Passenger " + (j + 1); } - const leftHeaderText = page.textInRect(0.0, 0.15, 0.33, 0.25); - const midHeaderText = page.textInRect(0.33, 0.15, 0.65, 0.25); - const rightHeaderText = page.textInRect(0.65, 0.15, 1.0, 0.25); - - const train = rightHeaderText.match(/(?:Train|Treno|Zug)(?:\/Train)?:[ \n](.*)\n/); - if (!train) { - break; + var coach = text.match(/(?:Coaches|Carrozza|Wagen|Voiture)(?:\/Coach)?: +(\S+)/); + if (coach) { + personalRes.reservedTicket.ticketedSeat.seatSection = coach[1]; } - res.reservationFor.trainNumber = train[1]; - const departure_time = leftHeaderText.match(/(\d{2}:\d{2}) - (\d{2}\/\d{2}\/\d{4})/) - const arrival_time = midHeaderText.match(/(\d{2}:\d{2}) - (\d{2}\/\d{2}\/\d{4})/) - res.reservationFor.departureTime = JsonLd.toDateTime(departure_time[2] + departure_time[1], "dd/MM/yyyyhh:mm", "it"); - res.reservationFor.arrivalTime = JsonLd.toDateTime(arrival_time[2] + arrival_time[1], "dd/MM/yyyyhh:mm", "it"); - - const dep = leftHeaderText.match(/(?:Stazione di Partenza|Departure station|Abfahrtsbahnhof|Gare de départ)(?:\/From)?\n+(.*)\n/); - res.reservationFor.departureStation.name = dep[1]; - const arr = midHeaderText.match(/(?:Stazione di Arrivo|Arrival station|Ankunft Bahnhof|Gare d'arrivée)(?:\/To)?\n+(.*)\n/); - res.reservationFor.arrivalStation.name = arr[1]; - - const barcodes = node.findChildNodes({ scope: "Descendants", mimeType: "internal/era-ssb", field: "issuerCode", match: "83" }).concat(node.findChildNodes({ scope: "Descendants", mimeType: "internal/uic9183", field: "carrierId", match: "83" })); - var offset = 0; - const passengerColumn = page.textInRect(0.0, 0.3, 0.27, 1.0); - for (let j = 0; j < barcodes.length; ++j) { - if (barcodes[j].location != i) { - continue; - } - let personalRes = JsonLd.clone(res); - var name = passengerColumn.substr(offset).match(/(?:Passenger Name|Nome Passeggero|Nom du Passager)(?:\/Passenger\n *name)?.*\n(?: .*\n)* *((?:\w+|\-\-).*?)(?: |\n)/); - offset += name.index + name[0].length; - if (name[1] !== "--") { - personalRes.underName.name = name[1]; - } else { - personalRes.underName.name = "Passenger " + (j + 1); - } - - var coach = text.match(/(?:Coaches|Carrozza|Wagen|Voiture)(?:\/Coach)?: +(\S+)/); - if (coach) { - personalRes.reservedTicket.ticketedSeat.seatSection = coach[1]; - } - - if (barcodes[j].result[0]['@type'] == 'TrainReservation') { - personalRes = JsonLd.apply(barcodes[j].result[0], personalRes); - } else { - personalRes.reservedTicket = JsonLd.apply(barcodes[j].result[0], personalRes.reservedTicket); - } - reservations.push(personalRes); + if (barcodes[j].result[0]['@type'] == 'TrainReservation') { + personalRes = JsonLd.apply(barcodes[j].result[0], personalRes); + } else { + personalRes.reservedTicket = JsonLd.apply(barcodes[j].result[0], personalRes.reservedTicket); } + reservations.push(personalRes); } return reservations; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-23.04.2/src/lib/uic9183/rct2ticket.cpp new/kitinerary-23.04.3/src/lib/uic9183/rct2ticket.cpp --- old/kitinerary-23.04.2/src/lib/uic9183/rct2ticket.cpp 2023-06-04 11:57:33.000000000 +0200 +++ new/kitinerary-23.04.3/src/lib/uic9183/rct2ticket.cpp 2023-07-04 07:16:41.000000000 +0200 @@ -217,7 +217,8 @@ static QString rct2Clean(const QString &s) { - if (s == QLatin1Char('*')) { // * is used to mark unset fields + // * is used to mark unset fields + if (std::all_of(s.begin(), s.end(), [](QChar c) { return c == QLatin1Char('*'); })) { return {}; } return s;