Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kitinerary for openSUSE:Factory checked in at 2026-11-06 19:30:37 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kitinerary (Old) and /work/SRC/openSUSE:Factory/.kitinerary.new.3759290 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kitinerary" Fri Nov 6 19:30:37 2026 rev:103 rq:1395286 version:26.08.3 Changes: -------- --- /work/SRC/openSUSE:Factory/kitinerary/kitinerary.changes 2026-10-10 14:56:50.734619326 +0200 +++ /work/SRC/openSUSE:Factory/.kitinerary.new.3759290/kitinerary.changes 2026-11-06 19:31:35.176926852 +0100 @@ -1,0 +2,18 @@ +Tue Nov 3 20:39:54 UTC 2026 - Christophe Marin <[email protected]> + +- Update to 26.08.3 + * New bugfix release + * For more details please see: + * https://kde.org/announcements/gear/26.08.3/ +- Changes since 26.08.2: + * Fix extracting arrival times for overnight Lufthansa flights + * Fix flight to train conversion in generic pkpass extraction + * Extract Lufthansa pkpass boarding passes for Deutsche Bahn + * lufthansa extractor: Allow a space before the slash + * Add extractor script for easyTable + * Consider literal prefixes at the start of an address line optional + * Extract Finnair PDF boarding passes in mobile layout + * Fix extracting LTG Link pkpasses using string-based date/time values + * fix ltglink PDF extractor for non-reservations + +------------------------------------------------------------------- Old: ---- kitinerary-26.08.2.tar.xz kitinerary-26.08.2.tar.xz.sig New: ---- kitinerary-26.08.3.tar.xz kitinerary-26.08.3.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kitinerary.spec ++++++ --- /var/tmp/diff_new_pack.5md2ag/_old 2026-11-06 19:31:36.049963325 +0100 +++ /var/tmp/diff_new_pack.5md2ag/_new 2026-11-06 19:31:36.051963409 +0100 @@ -18,11 +18,11 @@ %define kf6_version 6.27.0 %define qt6_version 6.9.0 -%define kpim6_version 6.8.2 +%define kpim6_version 6.8.3 %bcond_without released Name: kitinerary -Version: 26.08.2 +Version: 26.08.3 Release: 0 Summary: Data model and extraction system for travel reservations License: LGPL-2.1-or-later ++++++ kitinerary-26.08.2.tar.xz -> kitinerary-26.08.3.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.08.2/CMakeLists.txt new/kitinerary-26.08.3/CMakeLists.txt --- old/kitinerary-26.08.2/CMakeLists.txt 2026-10-06 05:08:07.000000000 +0200 +++ new/kitinerary-26.08.3/CMakeLists.txt 2026-11-02 19:40:58.000000000 +0100 @@ -7,10 +7,10 @@ # KDE Application Version, managed by release script set (RELEASE_SERVICE_VERSION_MAJOR "26") set (RELEASE_SERVICE_VERSION_MINOR "08") -set (RELEASE_SERVICE_VERSION_MICRO "2") +set (RELEASE_SERVICE_VERSION_MICRO "3") set (RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}") -set(PIM_VERSION "6.8.2") +set(PIM_VERSION "6.8.3") project(KItinerary VERSION ${PIM_VERSION}) set(QT_REQUIRED_VERSION "6.7.0") @@ -49,7 +49,7 @@ endif() set(KMIME_VERSION "6.7.0") -set(PIM_PKPASS "6.8.2") +set(PIM_PKPASS "6.8.3") find_package(KF6Mime ${KF_MIN_VERSION} CONFIG) if(NOT TARGET KF6::Mime) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.08.2/autotests/addressparsertest.cpp new/kitinerary-26.08.3/autotests/addressparsertest.cpp --- old/kitinerary-26.08.2/autotests/addressparsertest.cpp 2026-10-06 05:08:07.000000000 +0200 +++ new/kitinerary-26.08.3/autotests/addressparsertest.cpp 2026-11-02 19:40:58.000000000 +0100 @@ -10,6 +10,7 @@ #include <QTest> +using namespace Qt::Literals; using namespace KItinerary; #define s(x) QStringLiteral(x) @@ -35,6 +36,8 @@ QTest::newRow("PT-wrong-country") << s("1000-205 Lisboa") << s("1000-205 Lisboa") << QString() << s("DE"); QTest::newRow("AR-short") << s("C1420 Buenos Aires") << s("Buenos Aires") << s("C1420") << s("AR"); QTest::newRow("AR-full") << s("C1420ABC Buenos Aires") << s("Buenos Aires") << s("C1420ABC") << s("AR"); + QTest::newRow("FI-prefix") << u"FI-90100 Oulu"_s << u"Oulu"_s << u"90100"_s << u"FI"_s; + QTest::newRow("FI-noprefix") << u"90100 Oulu"_s << u"Oulu"_s << u"90100"_s << u"FI"_s; } void testPostalCodeExtraction() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.08.2/src/cli/org.kde.kitinerary-extractor.appdata.xml new/kitinerary-26.08.3/src/cli/org.kde.kitinerary-extractor.appdata.xml --- old/kitinerary-26.08.2/src/cli/org.kde.kitinerary-extractor.appdata.xml 2026-10-06 05:08:07.000000000 +0200 +++ new/kitinerary-26.08.3/src/cli/org.kde.kitinerary-extractor.appdata.xml 2026-11-02 19:40:58.000000000 +0100 @@ -135,6 +135,7 @@ </categories> <launchable type="desktop-id">org.kde.kitinerary-extractor.desktop</launchable> <releases> + <release version="6.8.3" date="2026-11-05"/> <release version="6.8.2" date="2026-10-08"/> <release version="6.8.1" date="2026-09-10"/> <release version="6.8.0" date="2026-08-20"/> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.08.2/src/lib/processors/pkpassdocumentprocessor.cpp new/kitinerary-26.08.3/src/lib/processors/pkpassdocumentprocessor.cpp --- old/kitinerary-26.08.2/src/lib/processors/pkpassdocumentprocessor.cpp 2026-10-06 05:08:07.000000000 +0200 +++ new/kitinerary-26.08.3/src/lib/processors/pkpassdocumentprocessor.cpp 2026-11-02 19:40:58.000000000 +0100 @@ -622,7 +622,7 @@ auto r = childResult(node).value<TrainReservation>(); if (!node.childNodes().empty() && !node.childNodes()[0].result().isEmpty() && JsonLd::isA<FlightReservation>(node.childNodes()[0].result().result().at(0))) { const auto flightRes = node.childNodes()[0].result().jsonLdResult().at(0).toObject(); - res = JsonLdDocument::apply(JsonLdDocument::fromJsonSingular(ReservationConverter::flightToTrain(flightRes)), res).value<TrainReservation>(); + r = JsonLdDocument::apply(JsonLdDocument::fromJsonSingular(ReservationConverter::flightToTrain(flightRes)), res).value<TrainReservation>(); } applyTicketToken(tokenFromBarcode(pass), r); r = extractTrainTicket(pass, r); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.08.2/src/lib/scripts/easytable.js new/kitinerary-26.08.3/src/lib/scripts/easytable.js --- old/kitinerary-26.08.2/src/lib/scripts/easytable.js 1970-01-01 01:00:00.000000000 +0100 +++ new/kitinerary-26.08.3/src/lib/scripts/easytable.js 2026-11-02 19:40:58.000000000 +0100 @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2026 Volker Krause <[email protected]> +// SPDX-License-Identifier: LGPL-2.0-or-later + +function extractEvent(ev) { + console.log(ev); + let res = JsonLd.newFoodEstablishmentReservation(); + res.reservationFor.name = ev.summary; + const addr = ev.location.split(/, /); + res.reservationFor.address.addressLocality = addr[addr.length - 1]; + addr.pop(); + res.reservationFor.address.streetAddress = addr.join(", "); + res.startTime = JsonLd.readQDateTime(ev, "dtStart"); + res.endTime = JsonLd.readQDateTime(ev, "dtEnd"); + return res; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.08.2/src/lib/scripts/easytable.json new/kitinerary-26.08.3/src/lib/scripts/easytable.json --- old/kitinerary-26.08.2/src/lib/scripts/easytable.json 1970-01-01 01:00:00.000000000 +0100 +++ new/kitinerary-26.08.3/src/lib/scripts/easytable.json 2026-11-02 19:40:58.000000000 +0100 @@ -0,0 +1,13 @@ +{ + "filter": [ + { + "field": "uid", + "match": "@easytable.com", + "mimeType": "internal/event", + "scope": "Current" + } + ], + "function": "extractEvent", + "mimeType": "internal/event", + "script": "easytable.js" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.08.2/src/lib/scripts/extractors.qrc new/kitinerary-26.08.3/src/lib/scripts/extractors.qrc --- old/kitinerary-26.08.2/src/lib/scripts/extractors.qrc 2026-10-06 05:08:07.000000000 +0200 +++ new/kitinerary-26.08.3/src/lib/scripts/extractors.qrc 2026-11-02 19:40:58.000000000 +0100 @@ -132,6 +132,8 @@ <file>easyairportparking-pkpass.js</file> <file>easyjet.json</file> <file>easyjet.js</file> + <file>easytable.json</file> + <file>easytable.js</file> <file>eckeroline.json</file> <file>eckeroline.js</file> <file>edreams.json</file> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.08.2/src/lib/scripts/finnair.js new/kitinerary-26.08.3/src/lib/scripts/finnair.js --- old/kitinerary-26.08.2/src/lib/scripts/finnair.js 2026-10-06 05:08:07.000000000 +0200 +++ new/kitinerary-26.08.3/src/lib/scripts/finnair.js 2026-11-02 19:40:58.000000000 +0100 @@ -13,13 +13,21 @@ function extractEticket(pdf, node, barcode) { // boarding pass if (barcode.content.repeatedMandatorySection(0).checkinSequenceNumber != 0) { + let res = node.result[barcode.location]; const page = pdf.pages[barcode.location].text; const depDt = page.match(/Departure.*\n(\d\d:\d\d)[, ]+(\d{2} \S{3} \d{4})/); - let res = node.result[0]; - res.reservationFor.departureTime = JsonLd.toDateTime(depDt[2] + ' ' + depDt[1], 'dd MMM yyyy HH:mm', 'en'); - const boarding = page.match(/Gate opens.*\n(\d\d:\d\d).*\nBoarding group.*\n(.*?) /); - res.reservationFor.boardingTime = JsonLd.toDateTime(boarding[1], 'HH:mm', 'en'); - res.boardingGroup = boarding[2]; + if (depDt) { + res.reservationFor.departureTime = JsonLd.toDateTime(depDt[2] + ' ' + depDt[1], 'dd MMM yyyy HH:mm', 'en'); + const boarding = page.match(/Gate opens.*\n(\d\d:\d\d).*\nBoarding group.*\n(.*?) /); + res.reservationFor.boardingTime = JsonLd.toDateTime(boarding[1], 'HH:mm', 'en'); + res.boardingGroup = boarding[2]; + return res; + } + // mobile boarding pass + const topLeft = pdf.pages[barcode.location].textInRect(0, 0, 0.5, 0.5); + const boarding = topLeft.match(/Group\n\s*(\S+) +(\S+) +(\S+)\n/); + res.boardingGroup = boarding[3]; + res.reservationFor.departureGate = boarding[2]; return res; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.08.2/src/lib/scripts/ltg-link.js new/kitinerary-26.08.3/src/lib/scripts/ltg-link.js --- old/kitinerary-26.08.2/src/lib/scripts/ltg-link.js 2026-10-06 05:08:07.000000000 +0200 +++ new/kitinerary-26.08.3/src/lib/scripts/ltg-link.js 2026-11-02 19:40:58.000000000 +0100 @@ -14,11 +14,16 @@ const dt = text.match(/(\d{4}-\d\d-\d\d)(?:\n.*){1,2}(\d\d:\d\d) - (\d\d:\d\d)/); res.reservationFor.departureTime = JsonLd.toDateTime(dt[1] + ' ' + dt[2], 'yyyy-MM-dd hh:mm', 'lt'); res.reservationFor.arrivalTime = JsonLd.toDateTime(dt[1] + ' ' + dt[3], 'yyyy-MM-dd hh:mm', 'lt'); - const train = text.match(/SEAT\n+ *(\S.*?) +(\S.*?) +(\S.*?) +(\S.*)\n/); - res.reservationFor.trainNumber = train[1]; - res.reservedTicket.ticketedSeat.seatingType = train[2]; - res.reservedTicket.ticketedSeat.seatSection = train[3]; - res.reservedTicket.ticketedSeat.seatNumber = train[4]; + const reservation = text.match(/SEAT\n+ *(\S.*?) +(\S.*?) +(\S.*?) +(\S.*)\n/); + if (reservation) { + res.reservationFor.trainNumber = reservation[1]; + res.reservedTicket.ticketedSeat.seatingType = reservation[2]; + res.reservedTicket.ticketedSeat.seatSection = reservation[3]; + res.reservedTicket.ticketedSeat.seatNumber = reservation[4]; + } else { + const trainNumber = text.match(/TRAIN[^\n]*\n(?:[^\n]*\n){1,4}\s*(\d+)\s+\d+/); + res.reservationFor.trainNumber = trainNumber[1]; + } res.reservedTicket.ticketToken = 'qrcode:' + triggerNode.content; return res; } @@ -29,16 +34,22 @@ '@type': 'TrainStation', name: pass.field['departure'].value }; - res.reservationFor.departureTime = JsonLd.readQDateTime(pass.field['departure_time'], 'value'); + + if (typeof pass.field['departure_time'].value === "string") { + res.reservationFor.departureTime = JsonLd.readQDateTime(pass.field['date'], 'value'); + res.reservationFor.arrivalTime = JsonLd.toDateTime(pass.field['arrival_time'].value, "HH:mm", "en"); + } else { + res.reservationFor.departureTime = JsonLd.readQDateTime(pass.field['departure_time'], 'value'); + res.reservationFor.arrivalTime = JsonLd.readQDateTime(pass.field['arrival_time'], 'value'); + } res.reservationFor.arrivalStation = { '@type': 'TrainStation', name: pass.field['destination'].value }; - res.reservationFor.arrivalTime = JsonLd.readQDateTime(pass.field['arrival_time'], 'value'); res.reservationFor.trainNumber = pass.field['line'].value; res.reservationFor.provider.identifier = "uic:1124"; res.reservedTicket.ticketedSeat.seatSection = pass.field['vehicle'].value; - res.reservedTicket.ticketedSeat.seatNumber = pass.field['seat'].value; + res.reservedTicket.ticketedSeat.seatNumber = pass.field['seat']?.value; const program = pass.field['campaign_ticket_code']; if (program) { res.programMembershipUsed = { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.08.2/src/lib/scripts/lufthansa-pkpass.js new/kitinerary-26.08.3/src/lib/scripts/lufthansa-pkpass.js --- old/kitinerary-26.08.2/src/lib/scripts/lufthansa-pkpass.js 2026-10-06 05:08:07.000000000 +0200 +++ new/kitinerary-26.08.3/src/lib/scripts/lufthansa-pkpass.js 2026-11-02 19:40:58.000000000 +0100 @@ -14,7 +14,11 @@ res.boardingGroup = pass.field["group"].value; } else { res.reservationFor.departureStation.name = pass.field["origin"].label; + res.reservationFor.departureStation.identifier = "iata:" + pass.field["origin"].value; res.reservationFor.arrivalStation.name = pass.field["destination"].label; + res.reservationFor.arrivalStation.identifier = "iata:" + pass.field["destination"].value; + res.reservationFor.arrivalTime = JsonLd.toDateTime(pass.field["arrivalTime"]?.value, "HH:mm", "de"); + res.reservationFor.trainNumber = pass.field["trainName"]?.value; } const back = pass.backFields; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.08.2/src/lib/scripts/lufthansa.js new/kitinerary-26.08.3/src/lib/scripts/lufthansa.js --- old/kitinerary-26.08.2/src/lib/scripts/lufthansa.js 2026-10-06 05:08:07.000000000 +0200 +++ new/kitinerary-26.08.3/src/lib/scripts/lufthansa.js 2026-11-02 19:40:58.000000000 +0100 @@ -83,7 +83,7 @@ res.reservationFor.boardingTime = JsonLd.toDateTime(boarding[2], 'hh:mm', 'en'); const leftCol = page.textInRect(0.0, 0.0, 0.65, 1.0); - const times = leftCol.match(/(\d\d:\d\d) +(\d\d:\d\d)\n/); + const times = leftCol.match(/(\d\d:\d\d) +(\d\d:\d\d)(?:\+1)?\n/); res.reservationFor.departureTime = JsonLd.toDateTime(times[1], 'hh:mm', 'en'); res.reservationFor.arrivalTime = JsonLd.toDateTime(times[2], 'hh:mm', 'en'); @@ -115,7 +115,7 @@ let reservations = []; let idx = 0; while (true) { - const leg = text.substr(idx).match(/([A-Z0-9]{2})(\d{1,4})\*? +(\d\d\S{3}\d\d) +(\d\d:\d\d) +(\S.*\S)\/([A-Z]{3}) +(\S.*\S)\/([A-Z]{3})/); + const leg = text.substr(idx).match(/([A-Z0-9]{2})(\d{1,4})\*? +(\d\d\S{3}\d\d) +(\d\d:\d\d) +(\S.*\S) ?\/([A-Z]{3}) +(\S.*\S) ?\/([A-Z]{3})/); if (!leg) break; idx += leg.index + leg[0].length; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.08.2/src/lib/scripts/lufthansa.json new/kitinerary-26.08.3/src/lib/scripts/lufthansa.json --- old/kitinerary-26.08.2/src/lib/scripts/lufthansa.json 2026-10-06 05:08:07.000000000 +0200 +++ new/kitinerary-26.08.3/src/lib/scripts/lufthansa.json 2026-11-02 19:40:58.000000000 +0100 @@ -3,7 +3,7 @@ "filter": [ { "field": "passTypeIdentifier", - "match": "pass.com.lufthansa.mbp", + "match": "pass.com.lufthansa.mbp|pass.com.digitalhangar.mbp", "mimeType": "application/vnd.apple.pkpass", "scope": "Current" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.08.2/src/lib/text/addressparser.cpp new/kitinerary-26.08.3/src/lib/text/addressparser.cpp --- old/kitinerary-26.08.2/src/lib/text/addressparser.cpp 2026-10-06 05:08:07.000000000 +0200 +++ new/kitinerary-26.08.3/src/lib/text/addressparser.cpp 2026-11-02 19:40:58.000000000 +0100 @@ -10,6 +10,7 @@ #include <QDebug> #include <QRegularExpression> +using namespace Qt::Literals; using namespace KItinerary; AddressParser::AddressParser() = default; @@ -119,7 +120,12 @@ QLatin1Char(')'); } if ((*it).isLiteral()) { - regex += (*it).literal(); + // allow the first literal to be missing, those are typically country-prefixes those postal codes + if (regex.size() == 1) { + regex += "(:?"_L1 + (*it).literal() + ")?"_L1; + } else { + regex += (*it).literal(); + } } }
